Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

PRIVATE type of PUBLIC procedure error: standard conformance question.

3 views
Skip to first unread message

Paul van Delst

unread,
Sep 12, 2007, 9:40:43 AM9/12/07
to
Hello,

I have the following module that defines a derived type:

module mytype_define
implicit none
private
public :: mytype_type
type :: mytype_type
integer :: i=0
end type mytype_type
end module mytype_define

and I have the following module that uses that derived type in an "application":

module mytype_application
use mytype_define, only: mytype_type
implicit none
private
! public :: mytype_type ! NOTE: Commented out
public :: mytype_test
contains
subroutine mytype_test( mytype )
type(mytype_type), intent(in out) :: mytype
mytype%i = mytype%i + 1
end subroutine mytype_test
end module mytype_application

The following program USEs both of these modules:

program test_mytype
use mytype_define
use mytype_application
implicit none
type(mytype_type) :: mytype
print *, mytype%i
call mytype_test(mytype)
print *, mytype%i
end program test_mytype

When I compile this with "g95 -std=f95" I get the error:

SUBROUTINE MyType_Test( MyType )
1
Error: Dummy argument 'mytype' at (1) cannot be a PRIVATE type of a PUBLIC procedure

(NOTE: compilation without the "-std=f95" switch works fine).

It is a sign that I'm getting too big for my boots that I almost immediately decided this
was a compiler bug. I contact AndyV and he pointed out to me that the above code is
non-conforming per section 5.2.3 of the f95 standard:

<quote>
Constraint: A module procedure that has a dummy argument or function result of a type that
has PRIVATE accessibility shall have PRIVATE accessibility and shall not have a
generic identifier that has PUBLIC accessibility.
</quote>

If I uncomment the line
! public :: mytype_type
in the application module, everything is honky dory. My question is this:

Does this constraint apply in this case? Given that the derived type is use associated,
should I also have to declare it as PUBLIC in the application module?

When I do the same standard-conformance-checking compile with gfortran,
gfortran -std=f95 Test_MyType.f90
and lahey,
lf95 --f95 Test_MyType.f90
I get no errors.

Overnight, Andy tells me he modified g95 to not report the error even with the -std=f95
switch.

So... what are people's considered opinions on this? I fear I've prompted Andy to "fix"
something that shouldn't have been fixed; if the code is non-standard, I would like the
compiler to tell me that.... even if the constraint is considered a silly one (that I'm
told has been removed from f2003)

cheers,

paulv

p.s. g95 and gfortran that I used for testing are the Sep 10 and Sep 11, 2007 versions
respectively.

Richard Maine

unread,
Sep 12, 2007, 12:17:54 PM9/12/07
to
Paul van Delst <Paul.v...@noaa.gov> wrote:

> Error: Dummy argument 'mytype' at (1) cannot be a PRIVATE type of a PUBLIC
procedure

...


> It is a sign that I'm getting too big for my boots that I almost
> immediately decided this was a compiler bug. I contact AndyV and he
> pointed out to me that the above code is non-conforming per section 5.2.3
> of the f95 standard:
>
> <quote> Constraint: A module procedure that has a dummy argument or
> function result of a type that has PRIVATE accessibility shall have
> PRIVATE accessibility and shall not have a generic identifier that has
> PUBLIC accessibility. </quote>

Andy can be forgiven for misreading this. The explanation for why he
misread it is quite subtle. It was an interp that took quite a long time
for J3 to straighten out. But there was an official interp on exactly
this. I've copied the official interp response below, but I'll try to
summarize it and make a few side points. (By the way, the interp took
longer to work than its history reflects; much of the history is in
interp 91, which ended up referencing this one for this material).

One side comment is that this "has" to the the answer or namespace
control of private types become virtually useless. But the standard
actually does support the answer as well... if you read carefuly enough.
I well recall the interp because I felt I had to argue it quite strongly
to avoid making a horrible mess of the standard in this area. Also,
several compilers got it "wrong" in their early releases; they were
eventually fixed after the interp came out.

Another side comment is that the restriction in question is "silly"
anyway. It was clearly written by people who didn't understand what
public and private attributes were about. Yes, I know they were on J3
and thus presumably involved in writing the stuff. That doesn't mean
that they understood what they had written (or perhaps it was different
people who wrote those parts - I wasn't there that early to know.) The
writers apparently had an incorrect notion (which I saw still there is
some much later debates on other topics), that the PRIVATE attribute
somehow was related to security and really kept the objects in question
restricted to the module. That is not how PRIVATE works or can
reasonably work. It isn't about security, but only about namespace
control. Declaring something PRIVATE is a declaration about the
identifier - not about the underlying object.

The restrition achieves nothing useful. All it does is prohibit some
perfectly sensible codes. It takes subtle argument (below) to fgure out
what codes it does prohibit. As it turns out, code like this isn't in
the prohibitted set, but even the code that is prohibitted "shouldn't"
be.

F2003 fixes the confusions and complications by just deleting the
restriction. But for F95...

The critical point lies in a very subtloe bit of working about what the
PUBLIC and PRIVATE attributes mean. You might be surprised to know that
although the PUBLIC attribute declares something to be public, the
PRIVATE attribute does not declare something to be private. I know it
sounds crazy, but that's not the way the standard describes it. I think
different terms should have been used, but it is way too late for that.
If you read carefully, you will see that the PRIVATE attribute declares
that an identifier is "not a public entity of that module". Note 2
things about this.

First, the strange negative form. Why say that it is not public instead
of using the positive form to say that it is private? Because it doesn't
mean that it is private! Read on to explain this apparent contradiction.

Second, note the "of that module". The entity still might be a public
entity of some other module. That is indeed the case here. An identifier
is only "really" private if it is declared to be private in the module
that defines it in the first place. If you USE the original module and
declare the indentifier PRIVATE in the second module, that doesn't
change the fact that the identifier is a public one of the original
module. It just means that the second module doesn't also export the
name.

------------------------------------------------------------------------
--------

NUMBER: 000161
TITLE: Modules and private derived types
KEYWORDS: module, private, derived type definition, structure component
DEFECT TYPE: Interpretation
STATUS: WG5 approved; ready for SC22

QUESTION: In compiling a Fortran 90 program, the following issues
came up:

Question 1:Section 4.4.1 (page 34) states:

"The accessibility of a derived type may be declared explicitly by
an
<access-spec> in its <derived-type-stmt> or in an <access-stmt>
(5.2.3).
The accessibility is the default if it is not declared explicitly.
If a
type definition is private, then the type name, the structure value
constructor (4.4.4) for the type, any entity that is of the type,
and any
procedure that has a dummy argument or function result that is of
the type
are accessible only within the module containing the definition."

Applying this to the following code:

MODULE M1
PRIVATE
TYPE FRED
INTEGER F1,F2
END TYPE FRED
TYPE(FRED), PUBLIC, PARAMETER :: Y=FRED(1,2)
TYPE(FRED), PUBLIC :: X
END

it can be seen that entities X and Y are accessible only within module
M1.

Is specifying the PUBLIC attribute for X and Y an error?

Question 2:Now what about this code:

MODULE M2
TYPE FRED
INTEGER F1,F2
END TYPE FRED
END

MODULE M3
USE M2
PRIVATE
TYPE(FRED), PUBLIC :: X
END

In module M3, the public type FRED imported from M2 becomes private. Is
the
declaration of X standard conforming?

The text in 4.4.1 is inadequate to cover this scenario. The declaration
should
be illegal but it depends on what is meant by "module containing the
definition"
in 4.4.1. The standard appears to describe the M1 case not the M3 case.
The
problem appears to be that module M2 contains the definition of the
public type
FRED and the module M3 contains the "definition" of the private type
FRED.

ANSWER 1: Yes.

ANSWER 2: Yes. The declaration of X in the module M3 is standard
conforming.

Discussion: The answer to question 2 depends on the interpretation of
what it
means for a module to "contain a definition" of a type.

The second paragraph of section 4.4.2 states:

"Two entities have the same type if they are declared with respect
to the same type definition. The definition may be accessed from
a module..."

This wording implies that module M3 does not contain a definition of the
type
FRED; it accesses the definition contained in module M2. Thus, it is
the
accessibility of FRED in module M2 that is referred to by the cited
paragraph
in 4.4.1.

In section 11.3.2, the last paragraph before the examples singles out
the PUBLIC
and PRIVATE attributes as different from all other attributes in that
they can
be respecified in a module that accesses an entity by use association.
This
paragraph also gives an interpretation to such respecification, stating
in part:

"If the name appears in a PRIVATE statement in a module, the entity
is not a public entity of that module."

Note specifically the phrase "of that module." The entity in question is
still a
public entity (of the module where it was defined). Nothing in any
scoping unit
other than the one where it was defined can change that. The effect of
a
PRIVATE statement in a module that accesses the entity by use
association is
just to prevent the "export" of the entity from that module - not to
make the
original entity private. The entity can still be accessed by using the
original module where it was defined. Only in the original module
containing
the definition does the PRIVATE attribute have the additional
interpretation of
actually making the entity private. It cannot actually be a private
entity of
any other module; note that the sentence quoted from section 11.3.2
avoids using
such wording, using instead the more awkward negative statement that it
is not a
public entity of that module.

A similar interpretation applies to the 4th constraint after R424 in
section 4.4.1:

"If a component of a derived type is of a type declared to be
private, either the derived type definition must contain the
PRIVATE statement or the derived type must be private."

If the type of a component is accessed by use association, then it must
have
been public in the module that defined it, so this constraint does not
apply.

The module

MODULE M4
USE M5
PRIVATE
PUBLIC X
END MODULE M4

is always legal if X is a public entity of M5. Suppose that M5 is

MODULE M5
USE M6
TYPE JOE
TYPE(RALPH) :: J1
END TYPE
TYPE(JOE) :: X
END MODULE M5

If the constraint in section 4.4.1 were interpreted differently, then
module M4
would have to declare at least JOE and RALPH to be public. It might
conceivably
also need to declare other names to be public; we cannot tell without
examining
at least module M6 and possibly other modules used in turn. This
dependence on
the details of the used modules would make an "object-oriented" style of
programming difficult. Module M4 does not have any obvious reason for
needing
to depend on the detailed structure of the type of X.

Note that a module can declare an object to be public when the type of
the
object is not even accessible in the module. For example

MODULE M7
USE M5, ONLY :: X
PRIVATE
PUBLIC X
END MODULE M7

Nowhere is there any restriction against this. Considering that module
M7 is
standard conforming, it would be strange if adding a "USE M5, ONLY: JOE"
suddenly made the "PUBLIC X" statement nonconforming.

EDIT: None
SUBMITTED BY: G. Barber
HISTORY: 93-290 m127 submitted
94-322 m131 answered, approved u.c.
95-034r1 m132 X3J3 ballot, approved 20-0; returned to subgroup
for editorial changes
95-086 m132 new version after editorial changes
95-281 m135 WG5 ballot approved
--
Richard Maine | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle | -- Mark Twain

Paul van Delst

unread,
Sep 12, 2007, 12:38:12 PM9/12/07
to
Richard Maine wrote:
> Paul van Delst <Paul.v...@noaa.gov> wrote:
>
>> Error: Dummy argument 'mytype' at (1) cannot be a PRIVATE type of a PUBLIC
> procedure
> ...
>> It is a sign that I'm getting too big for my boots that I almost
>> immediately decided this was a compiler bug. I contact AndyV and he
>> pointed out to me that the above code is non-conforming per section 5.2.3
>> of the f95 standard:
>>
>> <quote> Constraint: A module procedure that has a dummy argument or
>> function result of a type that has PRIVATE accessibility shall have
>> PRIVATE accessibility and shall not have a generic identifier that has
>> PUBLIC accessibility. </quote>
>

[snip]

> The critical point lies in a very subtloe bit of working about what the
> PUBLIC and PRIVATE attributes mean. You might be surprised to know that
> although the PUBLIC attribute declares something to be public, the
> PRIVATE attribute does not declare something to be private. I know it
> sounds crazy, but that's not the way the standard describes it. I think
> different terms should have been used, but it is way too late for that.
> If you read carefully, you will see that the PRIVATE attribute declares
> that an identifier is "not a public entity of that module". Note 2
> things about this.
>
> First, the strange negative form. Why say that it is not public instead
> of using the positive form to say that it is private? Because it doesn't
> mean that it is private! Read on to explain this apparent contradiction.
>
> Second, note the "of that module". The entity still might be a public
> entity of some other module. That is indeed the case here. An identifier
> is only "really" private if it is declared to be private in the module
> that defines it in the first place. If you USE the original module and
> declare the indentifier PRIVATE in the second module, that doesn't
> change the fact that the identifier is a public one of the original
> module. It just means that the second module doesn't also export the
> name.

Yes! This second point is exactly what I was wondering about - you stated it in a clear,
understandable way.

Thank you very much for the detailed reply. I was actually facing a situation like that
example in the interp with the M4, M5, M6 case where I would have to have cascading PUBLIC
declarations. All I can say is: phewph!

cheers,

paulv

0 new messages