Version 1.24 of ais/ai-00262.txt
!standard 10.01.02 (04) 05-07-11 AI95-00262/09
!standard 10.01.02 (08)
!class amendment 01-02-15
!status Amendment 200Y 02-07-11
!status WG9 Approved 02-12-13
!status ARG Approved 8-0-0 02-06-23
!status work item 02-05-23
!status ARG Approved 7-0-0 02-02-11
!status work item 01-02-15
!status received 01-02-15
!priority Medium
!difficulty Hard
!subject Access to private units in the private part
!summary
The context clause "private with" allows withing of private units in visible
unit specifications, and does not make the unit available in the visible part
of a package.
!problem
The private part of a package includes part of the implementation of the
package. For instance, the components of a private type may include handles
and other low-level data structures.
Ada 95 provides private packages to organize the implementation of a subsystem.
Unfortunately, these packages cannot be referenced in the private part of a
public package - the context clause for the private package is illegal.
This makes it difficult to use private packages to organize implementation
details of a subsystem.
For example, Claw puts most of the Win32 interface details into a set of
private packages. However, the inability to use the contents of those
packages in private parts meant that various workarounds had to be used:
Some types were moved to the ultimate parent package (for instance,
all of the handle types);
Many parameters and constants were declared to be of predefined types,
so that the predefined types could be used in the private part (thus
losing the benefits of strong typing);
Initializations of components were done in an Initialize routine in the
package body (so that the constants declared in the private packages
could be used).
All of this bending of the design was necessary because private packages
could not be referenced in the private part of a public package.
!proposal
We propose that the qualifier "private" is optionally added to with_clauses.
A library unit mentioned in a with_clause including the "private" qualifier
cannot be referenced in the visible part of the package. Otherwise, the
processing of with clauses is unchanged.
!wording
Change 10.1.2(4):
with_clause ::= [private] with library_unit_name {, library_unit_name};
Change 10.1.2(8):
If a with_clause of a given compilation_unit mentions a private child of some
library unit, then the given compilation_unit shall be one of:
* the declaration of a private descendant of that library unit;
* the body or subunit of a (public or private) descendant of that
library unit; or
* the declaration of a public descendant of that library unit, in which
case the with_clause shall include the reserved word private.
Add after 10.1.2(8):
A name denoting a library item that is visible only due to being mentioned in
one or more with_clauses that include the reserved word private shall appear
only within:
* a private part;
* a body, but not within the subprogram_specification of a library subprogram body;
* a private descendant of the unit on which one of these with_clauses
appear; or
* a pragma within a context clause.
!discussion
Private withs do not allow access to the library unit in the visible part of
the package or generic package. This rule is necessary to preserve the purpose
of 10.1.2(8): To prevent a private child from being visible (or even
semantically depended on) from outside the subsystem rooted at its
parent. [AARM 10.1.2(8.a)] This limitation has the pleasant side effect of
adding another capability beyond that described in the problem statement: it
allows the assertion that a unit (of any sort) will not be used in the public
part of a package. This additional documentation can be valuable to both users
and automated analysis tools. Some reviewers consider this capability more
important than withing private units.
Reference to private withed items in the private part is a legality rule,
rather than a visibility rule, in order to avoid a form of Beaujolais effect
when a declaration is moved from the visible part to the private part (or
vice-versa). Since such moves are common, it is important to avoid problems
with them. With the legality rule, the declarations will be illegal in the
public part.
For example:
package A is
function B return Integer;
end A;
function B return Integer;
with A;
private with B;
package C is
use A;
V1 : Integer := B; --
private
V2 : Integer := B; --
end C;
If we use a visibility rule saying that library subprogram B is not in scope
in the visible part of C, then the B at (1) resolves to A.B, while (2)
resolves to library unit B. Simply moving a declaration could silently change
its meaning: a classic Beaujolais effect. Removing "private" from with B would
have the same effect.
With the legality rule as proposed, the B at (1) is illegal. If the user meant
A.B, they can still say that.
Private withs are allowed on all compilation units. They are essentially
equivalent to a regular with on bodies. We considered making them illegal
on units other than (generic) package specifications, but that adds a rule
with little benefit to users.
Ada allows a unit to be withed multiple times in a single context clause. In
order to handle this, the legality rule is written so that if a unit is withed
by both a regular with and a private with, the legality rule does not apply.
Alternatively, we could have made such a combination illegal. But that doesn't
seem worthwhile, and it adds an additional new check.
The legality rule prohibits private withed units from being used in use_clauses
in context_clauses. Allowing this would substantially complicate the legality
rule for the use of such items, without much benefit. The user can always put
the use clause in the private part. Private withed units are allowed in
context clause pragmas such as Elaborate, since elaboration issues matter just
as much in the private part as in the rest of a package.
We cannot allow the use of private withed units in the subprogram_specification
part of a library subprogram body acting as a specification -- these are
visible declarations. For instance, if X is acting as a specification, then
A.T must be illegal in
private with A;
procedure X (Y : A.T) is
We simplify the check by simply saying that such uses are always illegal,
without requiring the compiler or user to figure out if it is acting as a body.
Any use in the subprogram specification of a body would have to be illegal
anyway (it could never conform to the original specification), so there is
no benefit to a more complex rule.
!example
As described in the problem statement, the low-level Win32 interface for Claw
is defined in a series of private packages. However, Ada 95 prevents these
packages from being accessed in the full types of private types. The proposed
feature eliminates that problem.
The low-level interface for an image list package might look like:
package Claw.Low_Level_Image_Lists is
type HImage_List is new DWord;
type IL_Flags is new UInt;
ILR_DEFAULTCOLOR : constant IL_Flags := 16#0000#;
ILR_MONOCHROME : constant IL_Flags := 16#0001#;
...
type Image_Kind_Type is (Bitmap, Icon, Cursor);
for Image_Kind_Type use (Bitmap => 0, Icon => 1, Cursor => 2);
function Image_List_Load_Image (
Name : in Claw.Win32.LPCStr;
Width : in Claw.Int;
Image_Kind : in Image_Kind_Type;
Flags : in IL_Flags) return HImage_List;
pragma Import (StdCall, Image_List_Load_Image,
"ImageList_LoadImageA");
...
end Claw.Low_Level_Image_Lists;
The high-level interface for the image list package might look like:
private with Claw.Low_Level_Image_Lists;
package Claw.Image_List is
type Image_List_Type is tagged private;
procedure Load_Image (Image_List : in out Image_List_Type;
Image : in String;
Monochrome : in Boolean := False);
...
private
type Image_List_Type is tagged record
Handle : Claw.Low_Level_Image_Lists.HImage_List;
Flags : Claw.Low_Level_Image_Lists.IL_Flags;
...
end record;
end Claw.Image_List;
A reference to Claw.Low_Level_Image_Lists would still be illegal in the visible
part of Claw.Image_List.
!corrigendum 10.1.2(04)
Replace the paragraph:
with_clause ::= with library_unit_name {, library_unit_name};
by:
with_clause ::= [private] with library_unit_name {, library_unit_name};
!corrigendum 10.1.2(08)
Replace the paragraph:
If a with_clause of a given compilation_unit mentions a private child
of some library unit, then the given compilation_unit shall be either the
declaration of a private descendant of that library unit or the body or subunit
of a (public or private) descendant of that library unit.
by:
If a with_clause of a given compilation_unit mentions a private child
of some library unit, then the given compilation_unit shall be one of:
- the declaration of a private descendant of that library unit;
- the body or subunit of a (public or private) descendant of that
library unit; or
- the declaration of a public descendant of that library unit, in which
case the with_clause shall include the reserved word private.
A name denoting a library item that is visible only due to being
mentioned in one or more with_clauses that include the reserved word
private shall appear only within:
- a body, but not within the subprogram_specification of a library subprogram body;
- a private descendant of the unit on which one of these
with_clauses appear; or
- a pragma within a context clause.
!ACATS test
A C-Test should be created to check that a private child can be private withed
into a sibling unit. A B-Test should be created to check that a private withed
library unit cannot be named in the visible part of a package or generic
package.
!appendix
From: Randy Brukardt [Randy@RRSoftware.Com]
Sent: Wednesday, February 14, 2001 1:54 PM
A recent discussion on comp.lang.ada proposed a "with private" context
clause, which would allow the withed entity to be used only in the private
part of a package.
The primary benefit of such a feature is that it would allow the use of
private packages in the private part of a public package. This is currently
impossible, and it forces reorganization of packages.
For instance, originally in Claw we put the low-level Win32 interface in a
series of private packages. However, these packages cannot be accessed in
the private part of the public types. That means that either we had to avoid
strong typing in the low-level interface, or abandon the private package
structure.
For instance, a possible image list package would look like:
package Claw.Low_Level_Image_Lists is
type HImage_List is new DWord;
type IL_Flags is new UInt;
ILR_DEFAULTCOLOR : constant IL_Flags := 16#0000#;
ILR_MONOCHROME : constant IL_Flags := 16#0001#;
...
type Image_Kind_Type is (Bitmap, Icon, Cursor);
for Image_Kind_Type use (Bitmap => 0, Icon => 1, Cursor => 2);
function Image_List_Load_Image (
Name : in Claw.Win32.LPCStr;
Width : in Claw.Int;
Image_Kind : in Image_Kind_Type;
Flags : in IL_Flags) return HImage_List;
pragma Import (StdCall, Image_List_Load_Image,
"ImageList_LoadImageA");
...
end Claw.Low_Level_Image_Lists;
with Claw.Low_Level_Image_Lists; -- Illegal!
package Claw.Image_List is
type Image_List_Type is tagged private;
procedure Load_Image (Image_List : in out Image_List_Type;
Image : in String;
Monochrome : in Boolean := False);
...
private
type Image_List_Type is tagged record
Handle : Claw.Low_Level_Image_Lists.HImage_List;
Flags : Claw.Low_Level_Image_Lists.IL_Flags;
...
end record;
end Claw.Image_List;
We ended up moving things to the private part of the parent (Claw) [which
makes it very large], eliminating some of the strong typing (since users
don't access this code, it only makes our job harder), and not bothering
with the private packages in the first place (putting the entire contents
into the private part of the Image_List package; but of course that mixes up
the high-level and low-level code).
----
I haven't yet looked at the visibility ramifications of such a feature, but
I will do so if there is sufficient interest in working out a full proposal.
****************************************************************
From: dewar@gnat.com
Sent: Wednesday, February 14, 2001 4:50 PM
<<The primary benefit of such a feature is that it would allow the use of
private packages in the private part of a public package. This is currently
impossible, and it forces reorganization of packages.>>
I think it has a much more significant benefit, which is that it makes
it easier to separate the public and private part into separate files,
where the private part has multiple implementations. We have often needed
that capability, and in fact on our enhancement list for GNAT is to allow
the private part to be in a separate file.
****************************************************************
From: Pascal Leroy [pleroy@rational.com]
Sent: Thursday, February 15, 2001 2:01 AM
> A recent discussion on comp.lang.ada proposed a "with private" context
> clause, which would allow the withed entity to be used only in the private
> part of a package.
I agree that this would be a very useful thing to have. There is another
benefit, in addition to the interaction with private children: by making a
with clause private, you ensure that in the course of maintenance it won't
be used to write declarations in the visible part, i.e., the stuff in the
withed unit won't be reexported.
Moreover, it seems quite easy to (1) specify in RM terms and (2) implement.
A much better usefulness/complexity ratio than extensible enums, if you ask
me.
****************************************************************
From: dewar@gnat.com
Sent: Thursday, February 15, 2001 12:15 PM
I very much agree with this asessment!
****************************************************************
From: Tucker Taft
Sent: Thursday, February 15, 2001 8:57 AM
Randy Brukardt wrote:
>
> A recent discussion on comp.lang.ada proposed a "with private" context
> clause, which would allow the withed entity to be used only in the private
> part of a package.
>
> The primary benefit of such a feature is that it would allow the use of
> private packages in the private part of a public package. This is currently
> impossible, and it forces reorganization of packages.
This is not a trivial change. Currently, private children are *never*
needed at compile-time of public specs (ignoring macro expansion
requirements related to generics and inlines, of course!). This
allows a strong physical separation between the public specs and the
"implementation" of a subsystem. I would be reluctant to see this
principle violated.
In fact, "private" children should more properly be
called "body" children.
>
> For instance, originally in Claw we put the low-level Win32 interface in a
> series of private packages. However, these packages cannot be accessed in
> the private part of the public types. That means that either we had to avoid
> strong typing in the low-level interface, or abandon the private package
> structure.
An alternative structure is to make these *public* packages
but with essentially all of their declarations in the private part.
Is there a reason why this wouldn't work?
>
> For instance, a possible image list package would look like:
>
> package Claw.Low_Level_Image_Lists is
> type HImage_List is new DWord;
> type IL_Flags is new UInt;
> ILR_DEFAULTCOLOR : constant IL_Flags := 16#0000#;
> ILR_MONOCHROME : constant IL_Flags := 16#0001#;
> ...
> type Image_Kind_Type is (Bitmap, Icon, Cursor);
> for Image_Kind_Type use (Bitmap => 0, Icon => 1, Cursor => 2);
>
> function Image_List_Load_Image (Name : in Claw.Win32.LPCStr;
> Width : in Claw.Int;
> Image_Kind : in Image_Kind_Type;
> Flags : in IL_Flags) return
> HImage_List;
> pragma Import (StdCall, Image_List_Load_Image,
> "ImageList_LoadImageA");
>
> ...
> end Claw.Low_Level_Image_Lists;
>
> with Claw.Low_Level_Image_Lists; -- Illegal!
> package Claw.Image_List is
> type Image_List_Type is tagged private;
> procedure Load_Image (Image_List : in out Image_List_Type; Image : in
> String;
> Monochrome : in Boolean := False);
> ...
> private
> type Image_List_Type is tagged record
> Handle : Claw.Low_Level_Image_Lists.HImage_List;
> Flags : Claw.Low_Level_Image_Lists.IL_Flags;
> ...
> end record;
> end Claw.Image_List;
>
> We ended up moving things to the private part of the parent (Claw) [which
> makes it very large], eliminating some of the strong typing (since users
> don't access this code, it only makes our job harder), and not bothering
> with the private packages in the first place (putting the entire contents
> into the private part of the Image_List package; but of course that mixes up
> the high-level and low-level code).
I would think public children with essentially all of their interesting
decls in their private part would help break these big private parts
up.
>
> ----
>
> I haven't yet looked at the visibility ramifications of such a feature, but
> I will do so if there is sufficient interest in working out a full proposal.
****************************************************************
From: Pascal Leroy
Sent: Thursday, February 15, 2001 9:50 AM
> An alternative structure is to make these *public* packages
> but with essentially all of their declarations in the private part.
> Is there a reason why this wouldn't work?
I don't understand this. Declarations in the private part are not visible
anyway, so what good would it do? Could you give an example of what you
have in mind?
****************************************************************
From: Randy Brukardt [Randy@RRSoftware.Com]
Sent: Thursday, February 15, 2001 11:49 AM
> An alternative structure is to make these *public* packages
> but with essentially all of their declarations in the private part.
> Is there a reason why this wouldn't work?
Sure, no one would have visibility on the declarations in the private part.
How could you use them?
You must have had something else in mind; could you recast my example as you
suggest?
****************************************************************
From: Tucker Taft
Sent: Thursday, February 15, 2001 12:11 PM
Pascal Leroy wrote:
>
> > An alternative structure is to make these *public* packages
> > but with essentially all of their declarations in the private part.
> > Is there a reason why this wouldn't work?
>
> I don't understand this. Declarations in the private part are not visible
> anyway, so what good would it do? Could you give an example of what you
> have in mind?
Good point. I realize I was misremembering a suggestion
by Robert Eachus. The "trick" is to have an immediate parent
which has all of its declarations in its private part, and then
use renaming to rename the child so that it is directly beneath
its grandparent. For example:
package Claw is
...
end Claw;
package Claw.Hidden is
private
-- lots of private junk
end Claw.Hidden;
package Claw.Hidden.Child is
-- useful stuff
private
-- Claw.Hidden private part is visible here
end Claw.Hidden.Child;
with Claw.Hidden.Child;
package Claw.Child renames Claw.Hidden.Child;
Not particularly elegant, but might solve the problem.
****************************************************************
From: Randy Brukardt
Sent: Thursday, February 15, 2001 1:49 PM
Well, Claw has 6 private low-level packages (otherwise, *they* get too
large -- Win32 is huge). Would you like to try this solution for a set of
interrelated private packages?? :-) :-)
This is, after all, essentially what we did to work around this problem: we
declared lots of stuff in the private part of the ultimate parent (Claw),
but the effect is to bloat that package. It doesn't provide a solution, just
a work-around.
****************************************************************
From: Randy Brukardt
Sent: Thursday, February 15, 2001 6:19 PM
We've gotten so fixed on Tucker's silly workaround suggestion that no one
has addressed his real concerns...
> This is not a trivial change. Currently, private children are *never*
> needed at compile-time of public specs (ignoring macro expansion
> requirements related to generics and inlines, of course!). This
> allows a strong physical separation between the public specs and the
> "implementation" of a subsystem. I would be reluctant to see this
> principle violated.
>
> In fact, "private" children should more properly be
> called "body" children.
You are forgetting that the private part of a spec really is part of the
*implementation* of a unit, not part of the specification. So, the current
situation is that part of the implementation can use private units, and part
don't.
If you really want to have this sort of physical separation, we have to have
some way to put private parts in a separate file. That seems like a much
more radical change than "with private" would be.
Given that Robert indicated that ACT was thinking about implementing
something on that line, perhaps it would be worthwhile to engage in a bit of
on-the-fly language design.
Here are my assumptions:
1) We don't want to change the invariant that the size of an Ada entity is
known once the spec is compiled. Eliminating that would be a massive change
to Ada compilers, and I really doubt that any such idea could get much
support from implementors.
2) We do want to allow a separate private part have its own context
clause, and allow private units to be withed there.
3) We need rules that would work both in source-based and "traditional"
compiler structures.
4) We don't need any additional functionality in the private part other
than (2).
(1) implies that the separate private part must be available when the
specification is compiled. For the "traditional" model, that means either it
must be compiled first (but what could that mean? It could depend on parts
of the spec) or compiled at the same time as the spec. For the
"source-based" model, this means that the source must be available when the
spec is compiled/used.
Assuming that the private part is available when the spec is compiled, the
separate private part would essentially be an "include" file, and shouldn't
cost much additional work in compilers. Most of the work would go into the
functionality of "with private".
Syntax for this seems hard to come up with. The best I can come up with
would be:
<context_clause>
package <Name> is
<public declarations>
private is separate;
end <Name>;
<context clause>
separate (<Name>)
package <Name> private is
<private declarations>
end <Name>;
Clearly, we would need a rule requiring the separate private to be available
when the spec is compiled -- and that is very different than other
separates, which are "real" separate compilation. We also would need to
extend the permissions in 10.1.4(7) to allow removing the spec from the
library when the private part is "added to the environment".
I guess my primary objection to this idea is that it isn't what it looks
like -- the private part is not really independent of the specification. But
that isn't necessarily a big deal (and different syntax might help here).
Tuck, would a proposal on this line address your objection??
****************************************************************
From: Robert A Duff
Sent: Thursday, February 15, 2001 8:14 PM
Randy suggests:
> Syntax for this seems hard to come up with. The best I can come up with
> would be:
>
> <context_clause>
> package <Name> is
> <public declarations>
> private is separate;
> end <Name>;
>
> <context clause>
> separate (<Name>)
> package <Name> private is
> <private declarations>
> end <Name>;
If I were designing the language from scratch, I would put the "imports"
(with_clauses) *inside* the thing importing. And the private part would
be a separate syntactic entity, presumably in a separate file. Or it
wouldn't exist at all.
But we're stuck with private parts. Sigh.
I suggest this syntax:
<context_clause>
package <Name> is
<public declarations>
end <Name>;
<context clause>
package <Name> private is
<private declarations>
end <Name>;
Presumably, most compilers would require that the private part "exist"
when compiling clients, and when compiling the visible part itself.
No need to make it look like a subunit, IMHO.
****************************************************************
From: Randy Brukardt
Sent: Thursday, February 15, 2001 8:33 PM
> I suggest this syntax:
>
> <context_clause>
> package <Name> is
> <public declarations>
> end <Name>;
>
> <context clause>
> package <Name> private is
> <private declarations>
> end <Name>;
>
> Presumably, most compilers would require that the private part "exist"
> when compiling clients, and when compiling the visible part itself.
> No need to make it look like a subunit, IMHO.
The problem with that is that a compiler couldn't tell the difference
between a package spec that has a separate private part, and one that has no
private part at all. We fixed problems like that in Ada 95, I don't think
we'd want to reintroduce them. So there has to be some sort of stub in the
package spec.
****************************************************************
From: Pascal Leroy
Sent: Friday, February 16, 2001 2:44 AM
> > This is not a trivial change. Currently, private children are *never*
> > needed at compile-time of public specs (ignoring macro expansion
> > requirements related to generics and inlines, of course!). This
> > allows a strong physical separation between the public specs and the
> > "implementation" of a subsystem. I would be reluctant to see this
> > principle violated.
I don't see why Tuck considers this principle so important. This is really
throwing the baby out with the bathwater. I have run into the problem
decribed by Randy several times myself (among other things, in implementing
some of the language-defined units, eg strings and I/O) and my conclusion
was that private units are like limited private types, they look nice but
are unusable in practice.
> > In fact, "private" children should more properly be
> > called "body" children.
>
> You are forgetting that the private part of a spec really is part of the
> *implementation* of a unit, not part of the specification. So, the current
> situation is that part of the implementation can use private units, and
> part don't.
Absolutely. This is why Tuck's principle is flawed in my opinion.
> If you really want to have this sort of physical separation, we have to have
> some way to put private parts in a separate file. That seems like a much
> more radical change than "with private" would be.
I don't like the direction that this discussion is taking. "with private"
is really quite simple, and I suspect we could come up with a proposal
and/or experimental implementations quickly, if we could overcome Tuck's
reluctance. On the other hand, separate private parts are a much bigger
change, especially for library-based compilers (I don't understand what it
means for the separate private part to be "available" when compiling the
spec; this doesn't make any sense for library-based compilers; if it did, we
would not have trouble with mutually-dependent packages).
> Given that Robert indicated that ACT was thinking about implementing
> something on that line...
And that's fine. First because GNAT can do what it wants in a non-standard
mode (I'm told that it can even compile C code in a non-standard mode :-)
and second because it's useful to do experiments on possible extensions to
the language.
But if we want a solution quickly (and that seems important because it is a
real problem that real people are having right now) then it will have to be
some form of "with private".
****************************************************************
From: Ehud Lamm
Sent: Friday, February 16, 2001 8:38 AM
>
> I don't like the direction that this discussion is taking. "with private"
> is really quite simple, and I suspect we could come up with a proposal
> and/or experimental implementations quickly, if we could overcome Tuck's
> reluctance.
I agree. It sems pretty much straightforward, and has some important
benefits for readability and maintenance. As this relates to layered
achitectural style, which I find to be the corner stone of abstraction, I
find this esp. important.
It also makes the progammers decision explicit: Does he want the unit to be
visibile in the public part of the spec? Making such decisions explicit was
mentioned in the steelman, and for good reasons.
****************************************************************
From: Robert A Duff
Sent: Friday, February 16, 2001 10:37 AM
Randy says:
> The problem with that is that a compiler couldn't tell the difference
> between a package spec that has a separate private part, and one that has no
> private part at all. We fixed problems like that in Ada 95, I don't think
> we'd want to reintroduce them.
We fixed one "problem" like that: optional package bodies. However, I
think that was a mistake. I think there *was* no language problem.
The problem was an implementation one: Ada 83 compilers ought to have
checked whether an optional body exists. They didn't, and that led to
the error-prone behavior.
Note that GNAT originally had the *same* error-prone behavior. If an
optional body existed on disk, GNAT would silently ignore it. GNAT
would only give the error message if you explicitly asked it to compile
the file, thus defeating the whole point of the new language rule
disallowing optional bodies. My point here is not to gripe about GNAT
(after all, they have long-since fixed that bug); my point is that this
is an issue of how you define what's in the program library (that is, an
implementation issue), and not a language issue.
>... So there has to be some sort of stub in the
> package spec.
I don't agree.
Pascal says:
> I don't like the direction that this discussion is taking. "with private"
> is really quite simple, and I suspect we could come up with a proposal
> and/or experimental implementations quickly, if we could overcome Tuck's
> reluctance. On the other hand, separate private parts are a much bigger
> change, ...
True. But "with private" seems aesthetically unappealing to me.
>...especially for library-based compilers (I don't understand what it
> means for the separate private part to be "available" when compiling the
> spec; this doesn't make any sense for library-based compilers; if it did, we
> would not have trouble with mutually-dependent packages).
I don't see what the big deal is. Your compiler has some file-naming
conventions (foo.1.ada, etc), so it seems like you could train it to
look for private parts according to some convention. Or require the
user to tell you where it is.
But if you and Randy both say so, I suppose I must be wrong.
> > Given that Robert indicated that ACT was thinking about implementing
> > something on that line...
>
> And that's fine. First because GNAT can do what it wants in a non-standard
> mode (I'm told that it can even compile C code in a non-standard mode :-)
> and second because it's useful to do experiments on possible extensions to
> the language.
Well, the feature won't be useful to *me* unless it's implemented by
more than just GNAT.
> But if we want a solution quickly (and that seems important because it is a
> real problem that real people are having right now) then it will have to be
> some form of "with private".
Perhaps you're right, but "with private" will look pretty silly if and
when we have private parts in separate files, or Tuck's suggestions
about putting things in the body.
****************************************************************
From: Randy Brukardt
Sent: Friday, February 16, 2001 10:37 PM
Bob says, replying to me:
> Randy says:
>
> > The problem with that is that a compiler couldn't tell the difference
> > between a package spec that has a separate private part, and one that has no
> > private part at all. We fixed problems like that in Ada 95, I don't think
> > we'd want to reintroduce them.
>
> We fixed one "problem" like that: optional package bodies. However, I
> think that was a mistake. I think there *was* no language problem.
> The problem was an implementation one: Ada 83 compilers ought to have
> checked whether an optional body exists. They didn't, and that led to
> the error-prone behavior.
In a library-based compiler, that is impossible. If the code hasn't been
submitted to the compiler, it doesn't know about it. In a source-based
compiler, that *might* be possible.
But in any case, that wasn't the problem. The problem with Ada 83 was that
if the body became obsolete, it silently disappeared from the program. Some
compilers gave warnings about this; but doing anything else was incorrect.
There even was an ACVC test to force this (non-friendly) behavior: Janus/Ada
gave a link error until we had to "fix" it to ignore the error in that one
special case just so we could validate.
In our case, at least we gave a warning, because we had to write a bunch of
extra code to make that ACVC test pass. The whole point of the change in Ada
95 was to get rid of that ACVC test.
> >... So there has to be some sort of stub in the
> > package spec.
>
> I don't agree.
I still don't agree with you.
Then Bob replies to Pascal:
> Pascal says:
>
> > I don't like the direction that this discussion is taking. "with private"
> > is really quite simple, and I suspect we could come up with a proposal
> > and/or experimental implementations quickly, if we could overcome Tuck's
> > reluctance. On the other hand, separate private parts are a much bigger
> > change, ...
>
> True. But "with private" seems aesthetically unappealing to me.
Can't argue with that. Which is why I suggested a brief foray into other
possible solutions.
> >...especially for library-based compilers (I don't understand what it
> > means for the separate private part to be "available" when compiling the
> > spec; this doesn't make any sense for library-based compilers; if it did, we
> > would not have trouble with mutually-dependent packages).
>
> I don't see what the big deal is. Your compiler has some file-naming
> conventions (foo.1.ada, etc), so it seems like you could train it to
> look for private parts according to some convention. Or require the
> user to tell you where it is.
>
> But if you and Randy both say so, I suppose I must be wrong.
You're wrong. :-)
For Janus/Ada, the compiler has no naming conventions. (The Make tool does,
but that's a different issue). The only units that the compiler (and program
library) knows about are those that it has been given to compile. There may
be other source laying around, but it is irrelevant.
To implement some sort of separate private part, we'd have to "pre-compile"
it (probably just do a syntax check) to insert it into the library; then it
would really be compiled when the stub was seen. Janus/Ada is syntax-based:
the only time it does something is when the syntax demands it. Thus, reading
the library happens only when there is a stub.
I think you're also putting a terrible burden on the reader of the source if
there is no indication that there is a private part missing. How would they
know if an "optional" private part (just like an optional body, not required
because there is nothing deferred) even exists? We don't want to design
features that make Ada HARDER to maintain.
Anyway, this would put a terrible new burden on the tools (especially the
make tool), and I suspect it will be a non-starter for that reason alone.
****************************************************************
From: Tucker Taft
Sent: Friday, February 16, 2001 8:46 AM
Randy Brukardt wrote:
>
> We've gotten so fixed on Tucker's silly workaround suggestion ...
Hey, I resent that ;-).
> ... that no one has addressed his real concerns...
>
> > This is not a trivial change. Currently, private children are *never*
> > needed at compile-time of public specs (ignoring macro expansion
> > requirements related to generics and inlines, of course!). This
> > allows a strong physical separation between the public specs and the
> > "implementation" of a subsystem. I would be reluctant to see this
> > principle violated.
> >
> > In fact, "private" children should more properly be
> > called "body" children.
>
> You are forgetting that the private part of a spec really is part of the
> *implementation* of a unit, not part of the specification. So, the current
> situation is that part of the implementation can use private units, and part
> don't.
I don't see it that way. When I present Ada to neophytes, I say
the visible part is the "logical interface" and the
private part of the spec is the "physical interface" and
the body is the "implemenation."
I think rather than trying to make private parts more sophisticated,
we should investigate simplifying them, and pushing more stuff
to the body. It is clear that in some cases, the size of a type
is not known at compile-time, e.g. when the type includes a nested
array component whose length is not known at compile time. This
implies that compilers have no problem dealing with such types,
and would seem a small step to introduce a kind of private
type where the full type information is deferred to the body.
(For compilers like RR where nested dynamic components are handled
with a level of indirection, clearly such a private type would also
involve a level of indirection.)
The other thing which really wants to be deferred to a body
is the full declaration for a deferred constant, so that large constant
tables can be given in a body rather than in a spec.
So...
How about something like:
type Priv(Discrim : Integer) is private;
Null_Priv : constant Priv;
private
type Priv(Discrim : Integer) is record in body;
Null_Priv : constant Priv in body;
Clearly declaring an object of type Priv or using Null_Priv implies
an elaboration check that the corresponding full declaration in the
body has been elaborated. Something like this additional elaboration
check will be needed in any case if we postpone elaboration of
the entire private part.
Of course only composite types could have their full declaration
postponed into the body. Otherwise pass by copy could be
truly nasty.
> ...
> Tuck, would a proposal on this line address your objection??
Not really. I prefer something more along the lines above, where
individual declarations can have their full definitions deferred
into the body.
****************************************************************
From: Robert A Duff [bobduff@world.std.com]
Sent: Friday, February 16, 2001 4:46 PM
> I don't see it that way. When I present Ada to neophytes, I say
> the visible part is the "logical interface" and the
> private part of the spec is the "physical interface" and
> the body is the "implemenation."
I think that view of private parts is rather unusual. I find it strange
to call the private part an "interface".
Do you consider a procedure body to be a "physical interface" in the
case where it is inlined? It's just like a private part, in the sense
that the compiler looks at it in order to generate (presumably better)
code.
The explanation I've heard many times (and agree with) is that the
private part contains stuff that logically belongs in the body, but for
efficiency, we want the compiler to be able to see it (when compiling
clients). In other words, it's an efficiency hack. Calling it an
"interface" of some sort seems to raise it to a higher level.
(In case you can't tell: If I were designing a language from scratch, it
would not have private parts. It would have package specs defining the
interface (and only the interface), and package bodies defining the
implementation. And in fact, I'm *always* designing a language, in my
head. It's my hobby. ;-))
> I think rather than trying to make private parts more sophisticated,
> we should investigate simplifying them, and pushing more stuff
> to the body.
This sounds like an excellent plan. Should have happened 20 years ago.
;-)
However, such a feature would be incomplete without a new pragma
analogous to Inline. This new pragma would tell the compiler to look at
the body of a with-ed package, and generate code that depends on the
full type and full constant declarations it finds there (eg, know the
size of a record at compile time, if possible). This is what pragma
Inline does for procedures: look at the package body, and depend on the
contents of the procedure body it finds there.
The effect on dependences and compilation order and whatnot for this new
pragma would be as for pragma Inline (and these effects depend on the
library model of that compiler).
If you use this pragma, you should get code (in client packages)
identical to what you get now, when you put the full type in the private
part, so the compiler can look at it.
This new pragma seems important to me: If you don't have it, you're
stuck with an annoying choice between efficiency at run time, versus
the benefits of putting the thing in the body: efficiency of compile
time, ability to "with" private children, better management of
source-file variants. Furthermore, if you put something in the body,
and you later decide that's too inefficient, you don't want to move it
to the private part, because that wrecks the structure of your program
-- you might have to rearrange all your packages, make private packages
public, etc. Much better to slap a pragma on it. Just like it's much
better to use pragma Inline than to hand-inline the code of that
procedure.
> It is clear that in some cases, the size of a type
> is not known at compile-time, e.g. when the type includes a nested
> array component whose length is not known at compile time. This
> implies that compilers have no problem dealing with such types,
> and would seem a small step to introduce a kind of private
> type where the full type information is deferred to the body.
> (For compilers like RR where nested dynamic components are handled
> with a level of indirection, clearly such a private type would also
> involve a level of indirection.)
>
> The other thing which really wants to be deferred to a body
> is the full declaration for a deferred constant, so that large constant
> tables can be given in a body rather than in a spec.
>
> So...
>
> How about something like:
>
> type Priv(Discrim : Integer) is private;
> Null_Priv : constant Priv;
>
> private
>
> type Priv(Discrim : Integer) is record in body;
Why "record"? Does the compiler need to know it's a record?
Is it allowed to be an array, task, protected?
> Null_Priv : constant Priv in body;
>
> Clearly declaring an object of type Priv or using Null_Priv implies
> an elaboration check that the corresponding full declaration in the
> body has been elaborated. Something like this additional elaboration
> check will be needed in any case if we postpone elaboration of
> the entire private part.
No, no, no! The proposal to split out the private part into a separate
syntactic entity, presumably in a separate source file, should *not*
change the run-time semantics in the slightest. The private part should
still be elaborated immediately after the visible part.
> Of course only composite types could have their full declaration
> postponed into the body. Otherwise pass by copy could be
> truly nasty.
Sigh.
> > ...
> > Tuck, would a proposal on this line address your objection??
>
> Not really. I prefer something more along the lines above, where
> individual declarations can have their full definitions deferred
> into the body.
I also prefer something along the lines of the above, but I still don't
understand Tuck's desire to preserve some sort of "physical interface".
If we have to have private parts, I don't see why they can't see private
children. But I agree with Tuck that moving information from private
parts to bodies is the right idea.
****************************************************************
From: Michael Yoder
Sent: Friday, February 16, 2001 7:01 PM
On this issue I agree with Pascal and Ehud. But let me start by quoting Bob
quoting Tucker:
> > I think rather than trying to make private parts more sophisticated,
> > we should investigate simplifying them, and pushing more stuff
> > to the body.
>
>This sounds like an excellent plan. Should have happened 20 years ago.
>;-)
[discussion of how Bob's ideal language would work snipped]
I'm skeptical we had the knowledge needed to do this right 20 years
ago. I'm skeptical we know *today* how to do it right. (Yes, it is
possible if code generation is always done at what we call "link
time.") But be that as it may, "with private" is preferable unless we can
finish all of Tucker's investigations in the reasonably near future. "With
private" cuts the Gordian knot and Tucker is advocating teasing it
apart. It would be better to do "with private" and then move towards a
Duffian or Taftian ideal language; if we arrive, "with private" and private
parts can then be made deprecated features.
I've often wanted to insert a second context clause right after the keyword
'private' in a package specification; each time my workaround was to
promote stuff I wanted in private packages into a public "wannabe private"
package.
> > > ...
> > > Tuck, would a proposal on this line address your objection??
> >
> > Not really. I prefer something more along the lines above, where
> > individual declarations can have their full definitions deferred
> > into the body.
>
>I also prefer something along the lines of the above, but I still don't
>understand Tuck's desire to preserve some sort of "physical interface".
>If we have to have private parts, I don't see why they can't see private
>children. But I agree with Tuck that moving information from private
>parts to bodies is the right idea.
I also prefer this, but I'd like to have "with private" in the interim
until I get all of it.
****************************************************************
From: Randy Brukardt
Sent: Friday, February 16, 2001 10:47 PM
Tucker said:
(Discussion of unusual world-view deleted :-)
> I think rather than trying to make private parts more sophisticated,
> we should investigate simplifying them, and pushing more stuff
> to the body. ...
> How about something like:
>
> type Priv(Discrim : Integer) is private;
> Null_Priv : constant Priv;
>
> private
>
> type Priv(Discrim : Integer) is record in body;
> Null_Priv : constant Priv in body;
>
>Clearly declaring an object of type Priv or using Null_Priv implies
>an elaboration check that the corresponding full declaration in the
>body has been elaborated. Something like this additional elaboration
>check will be needed in any case if we postpone elaboration of
>the entire private part.
I wouldn't be adverse to working on this idea further. It seems to just be
syntactic sugar for:
type Priv(Discrim : Integer) is private;
Null_Priv : constant Priv;
private
type <Anon_Priv> (Discrim : Integer); -- Deferred to body.
type Priv(Discrim : Integer) is access <Anon_Priv> (Discrim);
Null_Priv : constant Priv in body := <Anon_Null_Priv_Func>;
The only new thing about this would be the handling of the discriminants.
However, I think that the real-time and safety-critical people wouldn't be
happy: the last thing they want is more dynamic allocation of memory. They'd
probably never use this feature, and thus we'd still need "with private".
(I think Bob's pragma Inline for these is unworkable, since it couldn't be
implemented with link-time inlining; and thus would require library
dependencies that I simply will not stand for.)
****************************************************************
From: Robert A Duff
Sent: Saturday, February 17, 2001 9:43 AM
> I wouldn't be adverse to working on this idea further. It seems to just be
> syntactic sugar for:
>
> type Priv(Discrim : Integer) is private;
> Null_Priv : constant Priv;
>
> private
>
> type <Anon_Priv> (Discrim : Integer); -- Deferred to body.
> type Priv(Discrim : Integer) is access <Anon_Priv> (Discrim);
> Null_Priv : constant Priv in body := <Anon_Null_Priv_Func>;
>
> The only new thing about this would be the handling of the discriminants.
No, I don't think it's quite that simple. For Tucker's idea, you want
the compiler to manage the storage. For the incomplete type deferred to
the body (which was a younger Tucker's idea, by the way!), you have an
explicit access type, so the programmer is required to manage the
storage (which is why I never use that feature unless I wanted a pointer
type anyway).
> However, I think that the real-time and safety-critical people wouldn't be
> happy: the last thing they want is more dynamic allocation of memory. They'd
> probably never use this feature, and thus we'd still need "with private".
It's no more dynamic than an array of run-time-known size. That is,
it's not necessary to use the heap. (If some compilers choose to use
the heap, that's fine, but we should preserve the feasibility of never
using the heap except for explicit access types).
> (I think Bob's pragma Inline for these is unworkable, since it couldn't be
> implemented with link-time inlining; and thus would require library
> dependencies that I simply will not stand for.)
If some compilers can't implement the new pragma Inline, that's OK.
But I think it's extremely important to standardize the pragma,
so those compilers that care about this issue can support it
(portably!). Most compilers would in fact have no trouble implementing it.
****************************************************************
From: Randy Brukardt
Sent: Monday, February 19, 2001 4:16 PM
> No, I don't think it's quite that simple. For Tucker's idea, you want
> the compiler to manage the storage. For the incomplete type deferred to
> the body (which was a younger Tucker's idea, by the way!), you have an
> explicit access type, so the programmer is required to manage the
> storage (which is why I never use that feature unless I wanted a pointer
> type anyway).
I meant that to be implied. I should have added a Storage_Pool clause to
indicate that. I was mainly concerned about the code generation, which is the
same as above with an appropriate initialization New at each declaration.
Alternatively, I could have wrapped the access in a controlled type to do that.
Still, there is nothing new here...
> It's no more dynamic than an array of run-time-known size. That is,
> it's not necessary to use the heap. (If some compilers choose to use
> the heap, that's fine, but we should preserve the feasibility of never
> using the heap except for explicit access types).
I wasn't talking about the heap per-se. I don't think that the Safety-critical
people use dynamic arrays, either. That's because they don't want
non-deterministic memory usage. I stand by my comment.
****************************************************************
From: Pascal Leroy
Sent: Saturday, February 17, 2001 5:01 AM
Bob (who is always designing languages) explained:
> I think that view of private parts is rather unusual. I find it strange
> to call the private part an "interface".
>
> The explanation I've heard many times (and agree with) is that the
> private part contains stuff that logically belongs in the body, but for
> efficiency, we want the compiler to be able to see it (when compiling
> clients). In other words, it's an efficiency hack. Calling it an
> "interface" of some sort seems to raise it to a higher level.
I completely agree with this view. The notion that something which is
invisible to clients is an "interface" doesn't make sense to me.
Tuck proposed:
> > I think rather than trying to make private parts more sophisticated,
> > we should investigate simplifying them, and pushing more stuff
> > to the body.
I can agree with this, although as Bob pointed out we would want a pragma of
some sort (heck, it could be Inline applied to a type) to force the compiler
to generate decent code.
However, I believe we need to be pragmatic here. Pushing more stuff to the
body is probably sensible, but it is going to take several years to
refine/understand the consequences of this new model. On the other hand,
let me say it once more, "with private" could work tomorrow (tomorrow in ARG
terms probably means next year, I'm sure we all realize that). Also, we have
to keep in mind that there is a lot of code out there that uses private
parts, and restructuring that code to use the "in body" clause might be a
lot of work. On the other hand, adding "private" to a couple of with
clauses is an extremely cheap change.
So I guess I am saying that I like Mike Y's proposal:
> It would be better to do "with private" and then move towards a
> Duffian or Taftian ideal language; if we arrive, "with private" and private
> parts can then be made deprecated features.
****************************************************************
From: Robert A Duff
Sent: Saturday, February 17, 2001 9:37 AM
> I can agree with this, although as Bob pointed out we would want a pragma of
> some sort (heck, it could be Inline applied to a type) to force the compiler
> to generate decent code.
I almost suggested extending pragma Inline.
Of course it doesn't "force" anything -- it's your customers with open
checkbooks that do the forcing. ;-)
> So I guess I am saying that I like Mike Y's proposal:
>
> > It would be better to do "with private" and then move towards a
> > Duffian or Taftian ideal language; if we arrive, "with private" and private
> > parts can then be made deprecated features.
Sounds reasonable to me.
****************************************************************
From: Tucker Taft
Sent: Saturday, February 17, 2001 1:53 PM
> I almost suggested extending pragma Inline.
I think this somewhat defeats the purpose of the "in body."
I see the "in body" as allowing more dynamically constructed
systems. Pragma inline goes just the opposite, increasing
the amount of statically bound decisions. I also don't
see why this is expected to be so inefficient, given how often
one ends up with a dynamically-sized type already.
Perhaps the idea is that while the system is being developed, the
dynamic approach is great, but once you want to deliver the most
heavily optimized version, you can "inline" things. I can't imagine
going to the bother of using "in body" if you "inline" right away.
****************************************************************
From: Robert A Duff
Sent: Saturday, February 24, 2001 4:29 PM
> I think this somewhat defeats the purpose of the "in body."
I don't see how the mere existence of such a pragma defeats the
purpose. You don't have to use it.
Certainly, if you put the old kind of pragma Inline all over the place,
you somewhat defeat the purpose of separate compilation: you have to
regenerate code for calls when you change the body. But it's the
programmer's choice to make that trade-off.
My philosophy of pragma Inline is: I'm not trying to improve speed. I
have speed requirements. If I have pragma Inline, I have the freedom to
use procedural abstraction whenever I like, without worrying about
efficiency. Without pragma Inline, I have to perturb my design to
achieve efficiency.
I view my proposed Inline-like pragma the same way: I can freely put
this record type in a package body, because it makes sense to do so,
secure in the knowledge that if it's too slow, I can always "Inline"
it.
> I see the "in body" as allowing more dynamically constructed
> systems. Pragma inline goes just the opposite, increasing
> the amount of statically bound decisions.
Right, but the point is, you can choose the looser binding at the
expense of efficiency, or the other way around, at the drop of a hat.
>... I also don't
> see why this is expected to be so inefficient, given how often
> one ends up with a dynamically-sized type already.
I don't agree: I have lots of records that are compile-time-known size,
and I want the compiler to take advantage of that. More precisely, I
want the compiler to *be* *able* to take advantage of that, if I so
desire.
It's true that many things are dynamic-sized. But that does not imply
that if we make *everything* dynamic sized there's little cost.
> Perhaps the idea is that while the system is being developed, the
> dynamic approach is great, but once you want to deliver the most
> heavily optimized version, you can "inline" things.
Yes.
That's how I use pragma Inline already.
One point is that when I first write the code, I might not know which
way I want to do the trade-off. So I want to be able to change my mind,
without redesigning the structure of the program. Moving something from
body to private part is a big deal, because it rearranges the
with_clauses, and I might have to change private packages to public
(which ripples). Slapping on a pragma is much easier.
>... I can't imagine
> going to the bother of using "in body" if you "inline" right away.
First: I probably don't "inline_private" (or whatever it's called) right
away.
Second: Even if I do, I still get the advantage of textually separating
stuff out into the body.
Third: I would like a compiler option to turn off pragmas Inline (the
traditional variety, and the new one), so I can easily build my program
both ways.
****************************************************************
From: Robert A Duff
Sent: Saturday, February 17, 2001 9:53 AM
Randy says:
> In our case, at least we gave a warning...
Well, if you can give a warning, I don't see why you can't just as
easily give an error.
The implementation I'm imagining for a library-based compiler is that
the compiler has a rule that if there's a private part, you have to
submit it to the compiler at the same time as you submit the visible
part. Eg, if there's a command-line interface, you would type in two
file names. If you don't, and the private part turns out to exist at
link time, then complain.
But I'm not dead-set against having a stub-like syntax.
> I think you're also putting a terrible burden on the reader of the source if
> there is no indication that there is a private part missing.
I find that argument somewhat convincing. But not entirely.
When I want to know if a package body exists, I go and look at its file.
If that file doesn't exist, then the package body doesn't exist.
(I'm presumable either using some file-naming conventions voluntarily,
or else my compiler forces me to.) I certainly don't carefully read the
spec, to see if a body is required.
You also can't tell from a package spec whether any children exist.
So the private part doesn't seem like that big of a deal.
To tell whether it exists, go look for it in the directory where you
keep your source code.
****************************************************************
From: Pascal Leroy
Sent: Sunday, February 18, 2001 4:26 AM
So the model you have in mind is merely a #include, right? Fine, but that's
outside of the language in my opinion. I don't believe you can phrase the
above discussion in RM terms, i.e. "entered in the environment."
****************************************************************
From: dewar@gnat.com
Sent: Sunday, February 18, 2001 7:56 AM
<<We fixed one "problem" like that: optional package bodies. However, I
think that was a mistake. I think there *was* no language problem.
The problem was an implementation one: Ada 83 compilers ought to have
checked whether an optional body exists. They didn't, and that led to
the error-prone behavior.>>
I strongly disagree, suppose you had the following:
a spec p
a body p
where the body was not required
Now you build a program with the spec and body, and everything works
fine.
Now you edit the spec, and you recompile the spec, the body simply gets
left out.
What do you mean "check whether an optional body exists", you cannot
check if an optional body exists in the normal case, without searching
the universe. Yes, you can warn if one happens to be around, and you
can warn that one used to exist.
But you MUST be allowed (in Ada 83) to rebuild the executable with
only the new spec, and not the new body. The compiler cannot prevent
you from constructing this modified program, since it is legal.
The point in Ada 95 was to remove the requirement of being able to
construct the "wrong" program. Since every Ada 83 compiler had to
support this capability, and the capability itself is what was
fundamentally flawed, I think the change to Ada 95 was highly desirable.
<<Note that GNAT originally had the *same* error-prone behavior. If an
optional body existed on disk, GNAT would silently ignore it. GNAT
would only give the error message if you explicitly asked it to compile
the file, thus defeating the whole point of the new language rule
disallowing optional bodies. My point here is not to gripe about GNAT>>
That's completely confused, yes, that's a problem, one that might exist
in any compiler, but it has nothing whatsoever to do with the problem
we are talking about, and which this language solution exists.
The new Ada 95 feature is NOT talking about issues in building programs
in the first place, it is talking about the error prone behavior where
you modify a spec that does not require a body, and the modification
does not force a recompilation of the body. It is *ENTIRELY* that
modification scenario, required to "work" in all Ada 83 compilers
that the new Ada 95 feature is addressing.
What Bob Duff is referring wrt GNAT is that when you build a program
in the first place, where you have an improper body, then it is nice
if the automatic compilation tools make the effort to see if a body
is around (what on earth that means is of course very compilation
environment dependent). The "new" GNAT here searches everywhere on
the path for something that might be a body, and makes you get rid
of it. That's not always the right thing to do, but it is safer,
but this error check has nothing at all to do with the language
feature.
I am a bit surprised at this confusion, because this was a well
known problem in Ada 83, that was completely eliminated in Ada 95,
in all Ada 95 compilers, and in all versions of GNAT, and was a
welcome change in Ada 95.
Indeed if we have separated private parts, it is absolutely essential
in my view that we not repeat the mistake that Ada 83 made in this
area. Yes, you can defend against it to some limited extent by the
kind of peculiar searching around for possible peculiarities that
GNAT does, but that is not a desirable behavior.
Note incidentally that the RM appears to prohibit the GNAT behavior,
because there are specific rules about new units obsoleting old ones.
What we do for the ACVC runs is to use a crackpot (i.e. ACVC only)
script that sees GNAT issue the message of an unwelcome body or spec,
and then deletes it and transparently reattempts the compilation.
In other words, the following sequence must work as far as the
ACVC tests are concerned.
Introduce p.ads (spec needing body) and p.adb (body) into compilation
environment, and compile
Introduce new p.ads (spec not needing body) into compilation environment
and compile.
GNAT will reject the second attempt, but the ACVC test won't tolerate
that rejection, so we simply automatically delete the p.adb and proceed
(of course you would never want to do that automatically in real life,
which is why I call this a crackpot script).
****************************************************************
From: Tucker Taft
Sent: Saturday, February 17, 2001 1:47 PM
Pascal Leroy wrote:
> ...
> However, I believe we need to be pragmatic here. Pushing more stuff to the
> body is probably sensible, but it is going to take several years to
> refine/understand the consequences of this new model. On the other hand,
> let me say it once more, "with private" could work tomorrow (tomorrow in ARG
> terms probably means next year, I'm sure we all realize that).
I don't think this is a good argument. I really don't want to
add something and then soon thereafter declare it obsolescent.
On the other hand, I do see some value in "with private" though
I hate the name, since it brings up bad memories of an Ada 9X
proposal of the same name. Maybe "private with"? We aren't
"with"ing the private part, but rather "privately" withing the visible
part, so I think "private with" might make more sense anyway,
although it may be a bit trickier to parse.
I also don't think we should ignore the possibility of moving the
"with" clauses to immediately after the word "private".
I personally think we should drop discussion of physically separating
the "private" part, and leave that to compilers to do if they
so choose, especially if it is supposed to be completely
semantically neutral.
But getting back to "private with" -- exactly what was the proposal?
I have lost it in all the other discussion.
Clearly we can't allow a parent package spec to "with" its own
private children. So instead it must be siblings, nieces, etc.
that can "private with" their private siblings, aunts, etc.
I suppose an alternative is to simply allow these "with" clauses,
but then say that if the with'ed unit is private, it only becomes
visible in the private part. This is roughly equivalent to saying
that when a unit is "with"ed, if it is a private child, it
is implicitly inserted at the end of the private part of its parent,
while if it is a public child, it is implicitly inserted at the
end of the visible part of its parent. In any case, a spec
can never "with" its own descendant.
> ...
> So I guess I am saying that I like Mike Y's proposal:
>
> > It would be better to do "with private" and then move towards a
> > Duffian or Taftian ideal language; if we arrive, "with private" and private
> > parts can then be made deprecated features.
I really don't like this way of thinking. We should be convinced
that "private with" is useful indefinitely, rather than putting
it in as a stop-gap.
I see "private with" as serving a different purpose than
the "in body" stuff. It focuses on information hiding and
modularization, whereas the "in body" really opens up the
possibility for more dynamically constructed systems (similar to
the "with type" stuff).
****************************************************************
From: dewar@gnat.com
Sent: Sunday, February 18, 2001 9:13 AM
<<The explanation I've heard many times (and agree with) is that the
private part contains stuff that logically belongs in the body, but for
efficiency, we want the compiler to be able to see it (when compiling
clients). In other words, it's an efficiency hack. Calling it an
"interface" of some sort seems to raise it to a higher level.>>
This viewpoint seems exactly right in Ada 83, but surely is completely
wrong in Ada 95. The introduction of child packages that can see the
private part now means that indeed it is used as an interface for
the implementation, and I see Ada 95 code all the time where private
parts are full of subprogram specs that would never have fit the
Ada 83 model.
So I don't think you can turn back the clock at this stage, the nature
of private parts of packages has radically changed from the above
quoted viewpoint.
****************************************************************
From: Ehud Lamm
Sent: Monday, February 19, 2001 1:47 AM
Indeed. This is one prime reason to think that private parts as they are now
are problematic. They serve two very distinct semantic functions: to declare
implementation details that (per Ada-83) must be in the spec and to declare
the extension interface (similar to "protected" in C++).
I find the connection between child units and inheritance very elegant (see
Tucker Taft's LSN on this). However, outsiders (i.e., students) have a hard
time with this. Almost no one sees how to use the private part for extension
purposes unless told about this specifically.
I tried giving this as a riddle this semester ("Why does a pacakge have
procedures declared in the private part etc. etc.") and only one student
thought about child units.
However, I agree with Robert: We are too far into the game to change the
rules.
Notice that since the above means that the private part is indeed an
"interface" (that can be used only by children), it makes more sense to have
it _inside the spec_ and not in a seperate file. It is not just a hack for
storing impl. details: it is part of the abstraction. This is esp. true when
the essence of the package is to allow extension (e.g, when it declares
abstract tagged types; or in the future when it declares interfaces).
****************************************************************
From: Tucker Taft [stt@avercom.net]
Sent: Saturday, February 17, 2001 3:36 PM
Pascal Leroy wrote:
> Bob (who is always designing languages) explained:
>
> > I think that view of private parts is rather unusual. I find it strange
> > to call the private part an "interface".
> >
> > The explanation I've heard many times (and agree with) is that the
> > private part contains stuff that logically belongs in the body, but for
> > efficiency, we want the compiler to be able to see it (when compiling
> > clients). In other words, it's an efficiency hack. Calling it an
> > "interface" of some sort seems to raise it to a higher level.
>
> I completely agree with this view. The notion that something which is
> invisible to clients is an "interface" doesn't make sense to me.
Well, I won't belabor the point, but it is clearly an "interface"
from the compiler's point of view, and even from the programmer's
point of view, 'size is visible, as are various other properties
revealed only in the private part such as by-reference, atomic,
volatile, etc.
I call it the "physical" interface in analogy with the layers in
a network protocol. It is like the "physical link" level while
the visible part is more like the "application" level. Conceivably
you could put the code for the body of a procedure in some other
computer, but to communicate with it, you would need to know at
least something about the physical representation of the data you
pass to it.
****************************************************************
From: Ted Baker
Sent: Sunday, February 18, 2001 11:57 AM
> I think that view of private parts is rather unusual. I find it strange
> to call the private part an "interface".
>
> The explanation I've heard many times (and agree with) is that the
> private part contains stuff that logically belongs in the body, but for
> efficiency, we want the compiler to be able to see it (when compiling
> clients). In other words, it's an efficiency hack. Calling it an
> "interface" of some sort seems to raise it to a higher level.
The reason we want the compiler to be able to see it is that it
provides information that is NEEDED to implement the interface--
i.e., the lower-level details of the interface.
I realize that some people would like to move toward a more
dynamic, world, where no data representation details would need to
be bound by the interface. However, there will always remain
situations (e.g., interfacing to hardware and to code in other languages,
and -- dare I ever hope? -- interfacing to code compiled with
a different Ada compiler) where data representation will necessarily
be a logical part of the interface to a software component.
****************************************************************
From: dewar@gnat.com
Sent: Sunday, February 18, 2001 12:26 AM
<<I personally think we should drop discussion of physically separating
the "private" part, and leave that to compilers to do if they
so choose, especially if it is supposed to be completely
semantically neutral.>>
No one is suggesting that this be part of the definition, just that it
would be nice if whatever solution is decided here made it easier for
compilers to do this ...
****************************************************************
From: Pascal Leroy
Sent: Sunday, February 18, 2001 4:22 AM
> On the other hand, I do see some value in "with private" though
> I hate the name, since it brings up bad memories of an Ada 9X
> proposal of the same name. Maybe "private with"?
Ok, I changed the subject line of this message :-)
> We aren't
> "with"ing the private part, but rather "privately" withing the visible
> part, so I think "private with" might make more sense anyway,
> although it may be a bit trickier to parse.
I am not going to fight on the syntax, as long as the grammar remains
reasonably unambiguous.
> I also don't think we should ignore the possibility of moving the
> "with" clauses to immediately after the word "private".
I don't like that. It's good for readability to have the with clauses at
the beginning of the unit, it summarizes the dependencies of the unit, eg in
terms of compilation ordering. In fact, I believe that a number of "make"
tools out there work by scanning the beginning of the unit for withs and
separate. Now they would have to go much farther.
Also, it seems that you would have some trouble distinguishing pragmas that
appear in declarative parts from pragmas that appear in context clauses.
> I personally think we should drop discussion of physically separating
> the "private" part, and leave that to compilers to do if they
> so choose, especially if it is supposed to be completely
> semantically neutral.
I couldn't agree more.
> I suppose an alternative is to simply allow these "with" clauses,
> but then say that if the with'ed unit is private, it only becomes
> visible in the private part.
No, that's not sufficient. I believe you also want to "private with" public
units, but make it explicit that they are only needed for the private part.
That's useful for documentation and maintenance purposes. And maybe these
units will later turn into private units, but you don't want to do the
required restructuring right now. Again, think of all the code out there
that withs units for the sole purpose of writing a private part.
****************************************************************
From: Ehud Lamm
Sent: Sunday, February 18, 2001 8:57 AM
> > On the other hand, I do see some value in "with private" though
> > I hate the name, since it brings up bad memories of an Ada 9X
> > proposal of the same name. Maybe "private with"?
>
> Ok, I changed the subject line of this message :-)
I wouldn't fight over this... To my (non native) ears the first wording
sounds better.
>
> > I also don't think we should ignore the possibility of moving the
> > "with" clauses to immediately after the word "private".
>
> I don't like that. It's good for readability to have the with clauses at
> the beginning of the unit, it summarizes the dependencies of the unit, eg in
> terms of compilation ordering. In fact, I believe that a number of "make"
> tools out there work by scanning the beginning of the unit for withs and
> separate. Now they would have to go much farther.
I agree with Pascal. If/when the private part goes into a seperate file, the
with clauses might well follow, but as long as it remains in the spec, I
think the with clauses should stay where they are. Changing this can
introduce work and bugs to automatic tools, and is also bad for readability.
I think that it is again a situation of better being the enemy of good
enough. Unless the private part is eliminated, it is visible in the spec, so
why should we work hard to move the with clauses down a few lines?
> > I personally think we should drop discussion of physically separating
> > the "private" part, and leave that to compilers to do if they
> > so choose, especially if it is supposed to be completely
> > semantically neutral.
Quite. And this is why I agree that the with's should stay where they are,
for the time being.
****************************************************************
From: dewar@gnat.com
Sent: Monday, February 19, 2001 1:05 PM
<<I agree with Pascal. If/when the private part goes into a seperate file, the
with clauses might well follow, but as long as it remains in the spec, I
think the with clauses should stay where they are. Changing this can
introduce work and bugs to automatic tools, and is also bad for readability.
I think that it is again a situation of better being the enemy of good
enough. Unless the private part is eliminated, it is visible in the spec, so
why should we work hard to move the with clauses down a few lines?
>>
Note that the mere fact of the with's being at the top of the abstract
representation does not mean they have to be there in the physical
representation if you separate this into two separate files. There is
no rule that says that the only allowable way to split into two files
is to draw a line in the source :-)
****************************************************************
From: dewar@gnat.com
Sent: Sunday, February 18, 2001 8:49 AM
<<I agree. It sems pretty much straightforward, and has some important
benefits for readability and maintenance. As this relates to layered
achitectural style, which I find to be the corner stone of abstraction, I
find this esp. important.
It also makes the progammers decision explicit: Does he want the unit to be
visibile in the public part of the spec? Making such decisions explicit was
mentioned in the steelman, and for good reasons.>>
Note that it is possible to implement this right now without any change
to the language (we investigated this possibility some time ago). All
you need is a pragma
with x; pragma Private_Only (x);
that says that the unit x can only be referenced in the private part.
Now you can allow the private part to be in a separate file, with the
WITH clauses in that file (and no junk pragma), and you just declare
that this is a representation of the text where the WITH goes where
it belongs with the pragma.
But it is nicer if something like this is at least semi-standardized :-)
****************************************************************
From: Randy Brukardt
Sent: Monday, February 19, 2001 4:47 PM
No, this doesn't solve the problem. The problem is that it is illegal to
with a private package in a public specification. No pragma can change that
(unless of course you're in "extensions" mode).
Thus we need a real extension to allow such withing; the rest of it is
nice-to-have, but seems to come along for free.
****************************************************************
From: dewar@gnat.com
Sent: Monday, February 19, 2001 5:00 PM
Sure, I understand this, but in my view this is the nice-to-have feature,
the really essential one is to conveniently enable separated private parts.
For example, we often find that the copyright on the private part is
completely different from the copyright on the public part, and it
would really be nice to have two documents (e.g. this happens with
the RM defined library).
****************************************************************
From: Randy Brukardt
Sent: Monday, February 19, 2001 5:26 PM
Humm. The problem outlined on C.L.A., and which I described, and which we're
trying to solve in AI-262 is the private package needed by the private part
problem.
Separated private parts only came up as a possible solution to this problem.
In my opinion, they are a nice-to-have, while the private package problem
contorts designs (and essentially makes private packages useless for their
intended purpose); thus it has a much higher priority in my view.
****************************************************************
From: Randy Brukardt [Randy@RRSoftware.Com]
Sent: Monday, February 19, 2001 4:39 PM
> But getting back to "private with" -- exactly what was the proposal?
> I have lost it in all the other discussion.
I never worked out the exact details; I asked whether it was worth doing so,
and the rest is history... (and a very large appendix in AI-262, and a new
record in messages on Ada-Comment since I took it over).
****************************************************************
From: Christoph Grein [christoph.grein@eurocopter.de]
Sent: Monday, February 19, 2001 2:30 AM
To: ada-comment@ada-auth.org
Subject: Re: [Ada-Comment] Possible amendment: with private
> But getting back to "private with" -- exactly what was the proposal?
> I have lost it in all the other discussion.
package S is -- Note: not private, not in hierarchy T
...
end S;
-----------------------
package T is
...
end T;
-----------------------
private package T.Pr is
...
private
...
end T.Pr;
-----------------------
private with T.Pr, S;
pacakge T.C is
-- T.Pr, S invisible here
private
-- visible parts of T.Pr, S visible here
end T.C;
------------------------------------------------------------------
I'm not sure about the following:
private package X is -- Note: no visible parent (except of course Standard).
... -- Does such a package currently,
private -- i.e. without the proposed amendment,
... -- have any use?
end X;
-----------------------
private with X; -- should this be allowed?
package Y is -- Note: no hierarchical relation between X and Y
-- X invisible here
private
-- visible part of X visible here
end Y;
****************************************************************
From: Michael Yoder
Sent: Monday, February 19, 2001 4:20 PM
Tucker you wrote:
>Pascal Leroy wrote:
> > ...
> > However, I believe we need to be pragmatic here. Pushing more stuff to the
> > body is probably sensible, but it is going to take several years to
> > refine/understand the consequences of this new model. On the other hand,
> > let me say it once more, "with private" could work tomorrow (tomorrow
> in ARG
> > terms probably means next year, I'm sure we all realize that).
>
>I don't think this is a good argument. I really don't want to
>add something and then soon thereafter declare it obsolescent.
I absolutely agree. But I am nervous about this judgment unless we agree
on what "soon" means, and have strong confidence that we *can* declare it
obsolescent soon.
> > ...
> > So I guess I am saying that I like Mike Y's proposal:
> >
> > > It would be better to do "with private" and then move towards a
> > > Duffian or Taftian ideal language; if we arrive, "with private" and private
> > > parts can then be made deprecated features.
>
>I really don't like this way of thinking. We should be convinced
>that "private with" is useful indefinitely, rather than putting
>it in as a stop-gap.
>
>I see "private with" as serving a different purpose than
>the "in body" stuff. It focuses on information hiding and
>modularization, whereas the "in body" really opens up the
>possibility for more dynamically constructed systems (similar to
>the "with type" stuff).
Well, I may have misjudged by imagining that you and Bob were aiming at
nearly identical endpoints. I think that in Bob's ideal endpoint it would
become obsolete. I'm no longer sure about yours. If not, it would never
become a deprecated feature unless Bob converted you. :-)
****************************************************************
From: Robert A Duff
Sent: Saturday, February 24, 2001 4:11 PM
I've been away for a week, and I'm beginning to catch up on e-mail...
Mike Y says:
> On this issue I agree with Pascal and Ehud. But let me start by quoting Bob
> quoting Tucker:
>
>
> > > I think rather than trying to make private parts more sophisticated,
> > > we should investigate simplifying them, and pushing more stuff
> > > to the body.
> >
> >This sounds like an excellent plan. Should have happened 20 years ago.
> >;-)
> [discussion of how Bob's ideal language would work snipped]
>
> I'm skeptical we had the knowledge needed to do this right 20 years
> ago.
I should have said "I *wish* it had happened 20 years ago."
I didn't really mean to imply that the designers of Ada 83
were somehow negligent in not doing so.
>...I'm skeptical we know *today* how to do it right.
I'm quite sure that I could design a language from scratch with the
desired property (although I could not have done so 20 years ago!).
But I'm not so sure I know how to retrofit it into Ada, with the usual
constraints on upward compatibility, and not breaking everybody's
compiler. My approach is to think about what I really want in an ideal
world, and then think about how to fit it into the real world.
>... (Yes, it is
> possible if code generation is always done at what we call "link
> time.")
I don't intend to require link-time code generation.
****************************************************************
From: Robert A Duff
Sent: Saturday, February 24, 2001 4:40 PM
I wrote:
> > The implementation I'm imagining for a library-based compiler is that
> > the compiler has a rule that if there's a private part, you have to
> > submit it to the compiler at the same time as you submit the visible
> > part. Eg, if there's a command-line interface, you would type in two
> > file names. If you don't, and the private part turns out to exist at
> > link time, then complain.
Pascal replied:
> So the model you have in mind is merely a #include, right?
Pretty close. But I still expect a separate private part to be
separately parsed -- it's not like C, where the #include'd thing can be
any sequence of tokens. (Or is it even worse -- can C tokens span an
#include? I don't know C that well.)
>... Fine, but that's
> outside of the language in my opinion. I don't believe you can phrase the
> above discussion in RM terms, i.e. "entered in the environment."
I think I *can* phrase it in RM terms, as much so as current chap 10
stuff, which is always subject to crazy "source representation"
decisions by imaginary evil implementers.
The "environment" is the universe known to the compiler. Certainly, the
compiler defines that universe. But sane compilers define it sanely.
And whatever your compiler's notion of what exists in the universe, you
can tell (at link time) what exists in that universe.
****************************************************************
From: Robert A Duff
Sent: Saturday, February 24, 2001 5:00 PM
> <<We fixed one "problem" like that: optional package bodies. However, I
> think that was a mistake. I think there *was* no language problem.
> The problem was an implementation one: Ada 83 compilers ought to have
> checked whether an optional body exists. They didn't, and that led to
> the error-prone behavior.>>
>
> I strongly disagree, ...
OK, I retract my statement that there was no language problem.
Ada 83 required (or seemed to require) error-prone behavior.
However, I still say that we didn't need to fix it by
requiring/forbidding package bodies. I claim that optional package
bodies would be just fine (not error prone) given the Ada 95 library
model, and given sensible compilers.
GNAT defines the "environment" (the universe of source code) to be the
files you get when you say "ls *.ads *.adb" (in Unix). At least that's
the default, and you have search lists and whatnot, but anyway, there's
a clearly defined set of source files, well understood by the user. If
some of those are "optional" package bodies, what's the harm? If they
exist, they should be part of the program, if not, not.
Do you still "strongly disagree"?
>... suppose you had the following:
>
> a spec p
> a body p
> where the body was not required
>
> Now you build a program with the spec and body, and everything works
> fine.
>
> Now you edit the spec, and you recompile the spec, the body simply gets
> left out.
Yes, I now recall that this was required in Ada 83.
But it's not required in Ada 95. Ada 95 clearly allows an error message
in this case (I mean, Ada 95, modified to allow optional package
bodies).
> What do you mean "check whether an optional body exists", you cannot
> check if an optional body exists in the normal case, without searching
> the universe. Yes, you can warn if one happens to be around, and you
> can warn that one used to exist.
Right. You have to have some notion of "the universe", implementation
defined, but defined so that programmers can easily tell what's in the
universe. If so, programmers will never be surprised.
> <<Note that GNAT originally had the *same* error-prone behavior. If an
> optional body existed on disk, GNAT would silently ignore it. GNAT
> would only give the error message if you explicitly asked it to compile
> the file, thus defeating the whole point of the new language rule
> disallowing optional bodies. My point here is not to gripe about GNAT
> >>
>
> That's completely confused, yes, that's a problem, one that might exist
> in any compiler, but it has nothing whatsoever to do with the problem
> we are talking about, and which this language solution exists.
I don't see the difference. The body exists, it's optional, and the
compiler ignores it. That's a bug. I don't care whether I'm compiling
from scratch, or recompiling an existing program. In fact, in GNAT, it
doesn't matter which (which is good).
> The new Ada 95 feature is NOT talking about issues in building programs
> in the first place, it is talking about the error prone behavior where
> you modify a spec that does not require a body, and the modification
> does not force a recompilation of the body. It is *ENTIRELY* that
> modification scenario, required to "work" in all Ada 83 compilers
> that the new Ada 95 feature is addressing.
>
> What Bob Duff is referring wrt GNAT is that when you build a program
> in the first place, where you have an improper body, then it is nice
> if the automatic compilation tools make the effort to see if a body
> is around (what on earth that means is of course very compilation
> environment dependent). The "new" GNAT here searches everywhere on
> the path for something that might be a body, and makes you get rid
> of it. That's not always the right thing to do, but it is safer,
> but this error check has nothing at all to do with the language
> feature.
It seems to me that this is *always* the right thing to do, and GNAT is
entirely correct to complain about an optional body that exists (given
Ada 95's rule). GNAT defines its universe, and if that universe has junk
in it, complaints are warranted.
The earlier GNAT behavior was to define the optional body to not be part
of the universe. That's also RM-compliant behavior, but is obviously a
bug.
> I am a bit surprised at this confusion, because this was a well
> known problem in Ada 83, that was completely eliminated in Ada 95,
> in all Ada 95 compilers, and in all versions of GNAT, and was a
> welcome change in Ada 95.
>
> Indeed if we have separated private parts, it is absolutely essential
> in my view that we not repeat the mistake that Ada 83 made in this
> area. Yes, you can defend against it to some limited extent by the
> kind of peculiar searching around for possible peculiarities that
> GNAT does, but that is not a desirable behavior.
>
> Note incidentally that the RM appears to prohibit the GNAT behavior,
> because there are specific rules about new units obsoleting old ones.
> What we do for the ACVC runs is to use a crackpot (i.e. ACVC only)
> script that sees GNAT issue the message of an unwelcome body or spec,
> and then deletes it and transparently reattempts the compilation.
I do not agree that the RM prohibits the GNAT behavior.
(Exegesis available upon request.)
> In other words, the following sequence must work as far as the
> ACVC tests are concerned.
I'll bet these are legacy Ada 83 tests, and all right-thinking Ada 95
compiler writers should have challenged them. ;-) Yes, I know it's
easier to write a crackpot script. ;-)
> Introduce p.ads (spec needing body) and p.adb (body) into compilation
> environment, and compile
>
> Introduce new p.ads (spec not needing body) into compilation environment
> and compile.
>
> GNAT will reject the second attempt, but the ACVC test won't tolerate
> that rejection, so we simply automatically delete the p.adb and proceed
> (of course you would never want to do that automatically in real life,
> which is why I call this a crackpot script).
****************************************************************
From: Robert A Duff
Sent: Sunday, February 25, 2001 8:44 AM
> Yes, indeed you can handle things this way in the source based model, but
> that does NOT help you with the traditional library model implementation.
But the source-based folks have said that they give warnings -- they
could just as well give errors, except that the Ada 83 ACVC required
otherwise. So I claim that the only important *language* change in this
area was to make those tests invalid. And Ada 95 did that by allowing
implementations complete freedom to define what's in the "universe" (ie
the "environment).
****************************************************************
From: dewar@gnat.com
Sent: Sunday, February 25, 2001 10:44 AM
<<But the source-based folks have said that they give warnings -- they
could just as well give errors, except that the Ada 83 ACVC required
otherwise. So I claim that the only important *language* change in this
area was to make those tests invalid. And Ada 95 did that by allowing
implementations complete freedom to define what's in the "universe" (ie
the "environment).>>
My concern was with traditional library based implementations, not with
source based implementations. I don't see how they could know.
Remember that there must BE some mechanism in Ada 83 for
replacing
package spec + unneeded body
by
package spec without body
and I do not see how one could distinguish this legitimate conversion
from the accident in a library based environment. To require specific
deletion of the body would be worryingly extra-lingual.
In the source based model, GNAT is actually too fierce, it will NOT
let you compile a package spec that allows no body if there is a body
in sight, and insists that you get rid of the body first.
In ACVC mode, it actually deletes the source file, which is conforming,
but of course ludicrously hostile, so no one uses this weird ACVC
script in real life.
****************************************************************
From: Robert A Duff
Sent: Sunday, February 25, 2001 9:30 AM
> Note that it is possible to implement this right now without any change
> to the language (we investigated this possibility some time ago). All
> you need is a pragma
>
> with x; pragma Private_Only (x);
>
> that says that the unit x can only be referenced in the private part.
Well, maybe. What are the exact semantics? In particular, I had
assumed that if you say "private with X;", then the scope of that
with_clause does not include the visible part, so if there's a
use_clause in the visible part that makes some other X visible, it is
*not* hidden (in the vis part) by the library unit X. This seems
semantically nicest, and easiest to implement. But it seems in somewhat
bad taste for a pragma.
The alternative is to say that the scope of the with_clause includes the
visible part, but you're just not allowed to refer to X (as a separate
legality rule). This would mean that if you erase the pragma, the
program still works.
> Now you can allow the private part to be in a separate file, with the
> WITH clauses in that file (and no junk pragma), and you just declare
> that this is a representation of the text where the WITH goes where
> it belongs with the pragma.
It sounds like you're assuming the "alternative" semantics I described.
Otherwise, it's not simply a "source representation" issue.
> But it is nicer if something like this is at least semi-standardized :-)
Indeed. I wouldn't use the feature, unless I had some confidence in its
portability.
****************************************************************
From: dewar@gnat.com
Sent: Sunday, February 25, 2001 10:40 AM
<<The alternative is to say that the scope of the with_clause includes the
visible part, but you're just not allowed to refer to X (as a separate
legality rule). This would mean that if you erase the pragma, the
program still works.>>
Yes, that's my meaninvg of the pragma. Otherwise it is dubious indeed.
<<It sounds like you're assuming the "alternative" semantics I described.
Otherwise, it's not simply a "source representation" issue.>>
Yes indeed.
<<Indeed. I wouldn't use the feature, unless I had some confidence in its
portability.>>
My definition is completely portable, since there is a reliable
transformation from the separate files to a single file that has
standard Ada 95 semantics, and the compiler would guarantee that
this is the case.
At least in GNAT it is pretty easy to implement, because we always
keep track of what WITH's have actually been referenced (so that we
give warnings if they are unreferenced), and it is just a matter of
checking these flags at the start of the private part.
****************************************************************
From: Robert A Duff
Sent: Sunday, February 25, 2001 9:38 AM
> package S is -- Note: not private, not in hierarchy T
> ...
> end S;
> -----------------------
> package T is
> ...
> end T;
> -----------------------
> private package T.Pr is
> ...
> private
> ...
> end T.Pr;
> -----------------------
> private with T.Pr, S;
> pacakge T.C is
> -- T.Pr, S invisible here
Right, but are these things in scope? That is, can they hide other
things of the same name? I say, "No".
Note that Tucker's idea of actually moving the with_clauses, rather than
giving them a different syntax, better reflects the intended semantics
(assuming folks agree with my "No"). Surely everyone agrees with the
principle that syntax should reflect semantics!
> private
> -- visible parts of T.Pr, S visible here
> end T.C;
> ------------------------------------------------------------------
> I'm not sure about the following:
Yes, the following should be allowed. Standard is a perfectly good
library unit, and can have public and private children like any other.
Any other rule would be an unnecessary special case.
One possible use of private children of Standard is mentioned in
AARM-10.1.1(12.d).
> private package X is -- Note: no visible parent (except of course Standard).
> ... -- Does such a package currently,
> private -- i.e. without the proposed amendment,
> ... -- have any use?
> end X;
> -----------------------
> private with X; -- should this be allowed?
> package Y is -- Note: no hierarchical relation between X and Y
> -- X invisible here
> private
> -- visible part of X visible here
> end Y;
****************************************************************
From: Robert A Duff
Sent: Sunday, February 25, 2001 9:20 AM
> <<The explanation I've heard many times (and agree with) is that the
> private part contains stuff that logically belongs in the body, but for
> efficiency, we want the compiler to be able to see it (when compiling
> clients). In other words, it's an efficiency hack. Calling it an
> "interface" of some sort seems to raise it to a higher level.
> >>
Robert says:
> This viewpoint seems exactly right in Ada 83, but surely is completely
> wrong in Ada 95. The introduction of child packages that can see the
> private part now means that indeed it is used as an interface for
> the implementation, and I see Ada 95 code all the time where private
> parts are full of subprogram specs that would never have fit the
> Ada 83 model.
This is a good point.
However, I suspect that if private parts had never existed, then Tucker
would have invented child units that can see the body of their parent.
> So I don't think you can turn back the clock at this stage, the nature
> of private parts of packages has radically changed from the above
> quoted viewpoint.
OK, so I guess the right viewpoint is that private parts have a two-fold
purpose: the kludgy efficiency-hack purpose of Ada 83, and the
interface-for-children purpose of Ada 95. This implies that it is
worthwhile to investigate in two directions:
1. Moving stuff into the body that is now required to be in the
private part.
2. Separating out the private part, either physically or logically
or both. (By logically, I mean the "private with" idea, or the
idea of moving the with_clauses into the private part.)
My earlier implication, that (1) subsumes (2), is wrong. That is,
achieving (1) will *not* make "private with" obsolete. So we can make
Pascal (etc) happy by doing (2) soon, without holding things up for (1).
****************************************************************
From: Robert A Duff
Sent: Sunday, February 25, 2001 9:06 AM
Tucker says:
> I also don't think we should ignore the possibility of moving the
> "with" clauses to immediately after the word "private".
I am in favor of that idea.
I don't buy Pascal's objection that it's useful to see this stuff up
front. In fact, it damages readability to see it up front, because this
information is purely private. One should be able to read the public
information without being distracted. (I support the idea of physically
separating private parts for the same reason.)
I'm only mildly worried about the "simple minded tool" issue.
Better to improve the language than to worry about that.
> I personally think we should drop discussion of physically separating
> the "private" part, and leave that to compilers to do if they
> so choose, especially if it is supposed to be completely
> semantically neutral.
I don't agree.
Several folks have pointed out that implementations can do this anyway,
by inventing their own syntax that claims to "represent" the standard
Ada syntax. That's true from a legalistic point of view. However, from
a practical point of view, users will want all implementations to
support the same representation, or at least close enough that they can
expect reasonable portability at the source file level.
> But getting back to "private with" -- exactly what was the proposal?
> I have lost it in all the other discussion.
I'm not sure what exactly is the proposal, but I think it is attempting
to solve two separate problems:
1. It is currently difficult to tell whether a given with_clause is part
of the visible information about the package. It is desirable to mark
each with_clause with whether it applies to the visible part, or only to
the private part. To me, the ideal way to indicate this would be to
place the private with_clauses inside the private part, but some syntax
such as "private with" also solves the problem, albeit less readably.
2. It is currently illegal for a public library unit to "with" one of
its private siblings. Of course it only makes sense to do so if the
private sibling is used only in the private part of the importing
package. Tucker seems to think this is a feature; everybody else seems
to think it's a bug.
Note that (1) was a problem even in Ada 83, when child units and private
library units did not exist.
I believe Robert has stated that problem (1) is important to solve,
whereas (2) is merely nice to have. And Randy and Pascal have stated
that (2) is important, whereas (1) is merely nice to have. (Sorry if I
got that wrong -- I'm just trying to point out that folks disagree about
the priorities. I happen to think it would be nice to have a single
stone that kills both birds. I've been frustrated by both problems.)
> Clearly we can't allow a parent package spec to "with" its own
> private children. So instead it must be siblings, nieces, etc.
> that can "private with" their private siblings, aunts, etc.
>
> I suppose an alternative is to simply allow these "with" clauses,
> but then say that if the with'ed unit is private, it only becomes
> visible in the private part. This is roughly equivalent to saying
> that when a unit is "with"ed, if it is a private child, it
> is implicitly inserted at the end of the private part of its parent,
> while if it is a public child, it is implicitly inserted at the
> end of the visible part of its parent. In any case, a spec
> can never "with" its own descendant.
This idea solves problem (2), but not problem (1). We can solve both
problems at the same cost.
****************************************************************
From: dewar@gnat.com
Sent: Sunday, February 25, 2001 10:47 AM
<<I don't buy Pascal's objection that it's useful to see this stuff up
front. In fact, it damages readability to see it up front, because this
information is purely private. One should be able to read the public
information without being distracted. (I support the idea of physically
separating private parts for the same reason.)
>>
I agree that it is quite wrong to see this up front, in fact this makes
me realize that our headers are not quite right, we say:
-- This specification is derived from the Ada Reference Manual for use with --
-- GNAT. The copyright notice above, and the license provisions that follow --
-- apply solely to the contents of the part following the private keyword. --
But in fact the copyright also applies to the misplaced with's :-)
(legally, this is probably de minimus, still it is interesting to note
the intersection of technical and copyright concerns here :-)
****************************************************************
From: Randy Brukardt
Sent: Monday, February 26, 2001 5:41 PM
> I am in favor of that idea.
I object to this idea because it turns a "simple, easy" idea into one that
is much more complex to implement. That could easily tip the balance in
opposition to this feature. (It does for me.)
Implementing a with for which visibility appears at the private part seems
easy: we already have things that become visible at that point, and it
shouldn't be hard to add some additional ones. So the change is a tiny bit
of syntax and a bit hacking.
OTOH, for Janus/Ada, the "with" processing code was designed knowing that it
only was inserting into an empty (other than other withs) symboltable. It
wouldn't be possible to call it at the occurrence of "private" without a lot
of reworking. (Janus/Ada is an almost pure 1-pass compiler as far as
processing semantics is concerned.)
It would be possible, of course, to (logically) transform the program into
one where all of the context clauses are at the top -- but that would take a
substantial new mechanism that would be quite a bit more complex than
anything that we currently do. And, again, we would be substantially
reworking the "with" processing (in this case, to use the transformed
context clause rather than the one found in the syntax).
We also would have to get rid of the "fast" mode from our library management
tools, which assumes one unit per file (and thus, only reads the first few
lines to find the context clause).
I think the amount of work to implement that would outweigh any benefits (at
least until some customer with $$$$ cares), and thus I would probably have
to vote against it.
(This really begs the question of what we're doing here. If we're adding
small, important features to Ada 95 *now*, then making the feature more
complex than it has to be is a mistake. If we're really designing the next
revision of Ada, then the dynamic is quite different. The answer of what to
do is not always the same in both cases...)
****************************************************************
From: Robert A Duff
Sent: Sunday, February 25, 2001 9:49 AM
> Note that the mere fact of the with's being at the top of the abstract
> representation does not mean they have to be there in the physical
> representation if you separate this into two separate files. There is
> no rule that says that the only allowable way to split into two files
> is to draw a line in the source :-)
Well, Bob Duff has a personal rule that he's not willing to do fancy
editing to convert from one so-called "source representation" to
another. ;-)
If you give me a tool that does it automatically (or even tell me a
simple way to write one myself), and it guarantees the same exact
semantics, then OK.
I'm arguing from a purely practical point of view here. If we're
serious about putting private parts in separate files, there needs to be
a standard (concrete) syntax for doing so.
****************************************************************
From: dewar@gnat.com
Sent: Sunday, February 25, 2001 10:38 AM
<<Well, Bob Duff has a personal rule that he's not willing to do fancy
editing to convert from one so-called "source representation" to
another. ;-)>>
A reasonable rule :-)
<<I'm arguing from a purely practical point of view here. If we're
serious about putting private parts in separate files, there needs to be
a standard (concrete) syntax for doing so.>>
I would definitely prefer that this be the case ...
****************************************************************
From: Pascal Leroy
Sent: Tuesday, February 27, 2001 4:31 AM
> > I'm only mildly worried about the "simple minded tool" issue.
> > Better to improve the language than to worry about that.
>
> We also would have to get rid of the "fast" mode from our library management
> tools, which assumes one unit per file (and thus, only reads the first few
> lines to find the context clause).
I emphatically side with Randy here. The "simple minded tools" are very
important to the usability of compilation systems, and they are quite hard to
get right. Changing them can be a significant part of the effort involved, so
if we want to be serious in assessing the cost and benefits of any language
change, we have to look at the entire picture.
Our environment uses a "simple minded" parser to determine the compilation order
of units. This parser looks at the beginning of a file for the withs and
separate clause, and returns a skeleton Diana tree which we use to compute the
compilation order. With the proposed change this parser would have to become a
full-fledged parser because nearly every language construct can appear in the
visible part of a package (in particular, all the expression stuff would have to
be there). Moreover, we would lose a useful capability: with the current
mechanism, we are able to compute the compilation ordering even if units have
syntax errors. If we need to parse more text, it's likely that syntax errors
would cause us to give up and produce an incorrect ordering.
And then of course, there is this "simple minded tool" named ASIS, which we used
ubiquitously in our products. Adding a new predicate to ask whether a with
clause is a "private with" looks easy. Adding a new context_clause after the
word private would require substantial restructuring of the interfaces that
analyze compilation units.
****************************************************************
!topic Extending the private part of a package
!reference RM95-10.1.2(8)
!from Michael Gray
!sent Thursday, May 17, 2001 7:22 AM
!discussion
This issue was raised in reference to child packages. The spec of a child
package can be regarded as an extension to the spec of its parent (Rationale
II.7, "We can think of the child package as being declared inside the
declarative region of its parent but after the end of the specification of
its parent; most of the visibility rules stem from this model.") However, a
private child cannot be used as an extension of the private part of its
parent. This is because a private child is not visible to the same set of
places that its parent's private part is visible to; specifically, it is not
visible to the private parts of its siblings, whereas its parent's private
part is. There seems to have been some ambiguity about this in the
development of Ada95; Rationale section II.8 says "The other extra rule is
that the visible part of the private child can access the private part of
its parent. This is quite safe because it cannot export information about a
private type to a client because it is not itself visible. Nor can it export
information indirectly via its public siblings because, as mentioned above,
it is not visible to the visible parts of their specifications but only to
their private parts and bodies." I.e. this is saying that a private package
is visible to the private part of its public siblings, which is in flat
contradiction to LRM 10.1.2 (8), "If a with_clause of a given
compilation_unit mentions a private child of some library unit, then the
given compilation_unit shall be either the declaration of a private
descendant of that library unit or the body or subunit of a (public or
private) descendant of that library unit." This rule prevents a public
package "with"ing its private sibling, which therefore prevents the private
part of the public package getting visibility of its private sibling. We
cannot see a reason for this restriction.
The situation arose in the following context. We had a 'framework' of
packages A and A.B. We wished to provide a number of 'concrete' extensions
A.X and A.B.X; A.Y and A.B.Y; etc, where A.X etc are private (they are
intended for use only by A.B.X). But this was impossible because although
A.B's private part has visibility of A's private part, A.B.X's private part
does not have visibility of A.X's private part, because A.B (and therefore
A.B.X) cannot 'with' its private sibling A.X.
****************************************************************
From: Randy Brukardt
Sent: Friday, May 25, 2001 9:53 PM
The reason for the restriction is to prevent re-export of information from a
private package, and to prevent units outside of the "subsystem" from
depending on the private package. See AARM 10.1.2(8.a-l) for some commentary
on this.
On the other hand, there is a proposal on the table (AI-262) for "private
with"s, which would allow withing packages only to be used in the private
part of a package. This also would allow the withing of private packages in
the specs of sibling packages. This is discussed in AI-262, which isn't
written up yet. Does this seem like it would solve your problem??
****************************************************************
From: Michael Gray
Sent: Tuesday, May 29, 2001 6:02 AM
> The reason for the restriction is to prevent re-export of information from a
> private package, and to prevent units outside of the "subsystem" from
> depending on the private package. ...
Sure, I understand that. What I meant was, we couldn't see a reason why the
language should not make the content of a private package visible to the
/private/ part of its sibling.
> ... Does this seem like it would solve your problem??
Yes it does.
I had been thinking along the following lines: if A.B is a public child and
A.C a private child, then A.B should be able to "with" A.C, such that this
would give /only/ the private part of A.B visibility of A.C. But having
skimmed the 26 pages of AI-262, I agree that it would be better to have some
"private with" syntax by which context clauses that are needed only by the
private part of a package can be differentiated from context clauses that
are needed by the visible part (or both parts).
****************************************************************
From: Tucker Taft
Sent: Wednesday, May 22, 2002 8:32 PM
Baird, Steve wrote:
>1) Does AI-262 (private withs) result in the following
> program being incorrectly accepted?
>
> package Pkg is
> end Pkg;
>
> private procedure Pkg.Proc;
>
> private with Pkg.Proc;
> package Pkg.Child is
> generic
> with procedure Proc is <>;
> package G is
> end G;
>
> package I is new G;
> end Pkg.Child;
>
> Clearly Pkg.Child would be rejected if the instantiation's
> parameter were specified explicitly, but does the wording
> of the AI cover the defaulted case?
>
I don't see a problem here. This is a case where the use of an equivalence
rule saves us (now that's unusual ;-). 12.6(10) says that omitting an
actual subprogram when the default is a box is equivalent to an
explicit actual parameter that is a usage name identical to the
defining name of the formal.
On the other hand, now that I look more closely at the suggested wording
that is to follow 10.1.2(8), it seems like it has a fundamental problem.
Here is the wording, to remind people:
>A name shall not denote a declaration mentioned only in a with_clause which
>includes the reserved word private if:
> * the name appears in the visible part of a package or generic package, or
> * the name appears in a use_clause in a context_clause.
This talks about the visible part of *a* package. That seems overly
general. If a subpackage is entirely located within the private part,
then it should be OK to denote a privately-withed unit. I can imagine
at least two more reasonable rules: One is that a name denoting a
privately-withed unit shall not appear within the visible part of
*the* compilation unit. Alternatively, such a name is allowed only
within the private part, body, or descendant of a unit within the scope
of the private with clause.
The latter rule allows uses within the private part of visible
sub-packages, which seems to have been the intent of the original
wording. The latter rule would benefit from the definition of the notion
of a "visible place," as opposed to simply a "visible part of an entity"
which is what 8.2 defines, or the visibility of a declaration which
is what 8.3 defines. Note that AI-195 would also benefit from
the definition of a "visible place." An attribute definition would
be "available" if it appeared in a "visible place."
So let me formally suggest we define what it means for a "place"
to be visible, and then we could say that a reference to a privately-withed
unit would not be legal in a place that is visible outside the
declarative region of the library package or generic library package.
Similar wording could be used in AI-195, rather than the awkward
wording saying an attribute definition is available if it is
in a place where a declaration would have been visible.
Clearly once we have the definition for a "visible place," we can
use it for attribute definitions, pragmas, declarations, and
references.
****************************************************************
From: Randy Brukardt
Sent: Wednesday, June 12, 2002 9:04 PM
Tucker wrote (a long time ago):
> On the other hand, now that I look more closely at the uggested wording
> that is to follow 10.1.2(8), it seems like it has a fundamental problem.
> Here is the wording, to remind people:
>
> >A name shall not denote a declaration mentioned only in a with_clause which
> >includes the reserved word private if:
> > * the name appears in the visible part of a package or generic
> > package, or
> > * the name appears in a use_clause in a context_clause.
> >
>
> This talks about the visible part of *a* package. That seems overly
> general. If a subpackage is entirely located within the private part,
> then it should be OK to denote a privately-withed unit. I can imagine
> at least two more reasonable rules: One is that a name denoting a
> privately-withed unit shall not appear within the visible part of
> *the* compilation unit. Alternatively, such a name is allowed only
> within the private part, body, or descendant of a unit within
> the scope of the private with clause.
>
> The latter rule allows uses within the private part of visible
> sub-packages, which seems to have been the intent of the original
> wording.
Please do not assume the intent of the author. The author does not claim to
have thought about nested packages. :-)
> The latter rule would benefit from the definition of the notion
> of a "visible place," as opposed to simply a "visible part of an entity"
> which is what 8.2 defines, or the visibility of a declaration which
> is what 8.3 defines. Note that AI-195 would also benefit from
> the definition of a "visible place." An attribute definition would
> be "available" if it appeared in a "visible place."
>
> So let me formally suggest we define what it means for a "place"
> to be visible, and then we could say that a reference to a privately-withed
> unit would not be legal in a place that is visible outside the
> declarative region of the library package or generic library package.
> Similar wording could be used in AI-195, rather than the awkward
> wording saying an attribute definition is available if it is
> in a place where a declaration would have been visible.
>
> Clearly once we have the definition for a "visible place," we can
> use it for attribute definitions, pragmas, declarations, and
> references.
This latter proposal seems too complex to me.
However, Tucker is thinking too much about nested packages, and forgot about
children. It is important the rule applies to any children which inherit the
private with. (I was thinking about children, and forgot about nested
packages. So I guess we're even.)
Anyway, to clarify the issue, and to work through to a solution, consider
the following program:
private with Priv;
package Pack is
A : Integer := Priv.Int; -- Error.
package Nest is
B : Integer := Priv.Int; -- Error.
private
C : Integer := Priv.Int; -- ??.
end Nest;
private
D : Integer := Priv.Int; -- OK.
package Nesting is
E : Integer := Priv.Int; -- ??.
private
F : Integer := Priv.Int; -- OK.
end Nesting;
end Pack;
package Pack.Child is -- Inherits the private with.
G : Integer := Priv.Int; -- Better be illegal!
private
H : Integer := Priv.Int; -- OK.
end Pack.Child;
It is clear that A and B must be illegal, and D and F must be legal, in
order for "private with" to make any sense. The question is whether C and E
ought to be legal. Similarly, in the child, G must be illegal, and H must be
legal.
The existing rule:
A name shall not denote a declaration mentioned only in a with_clause which
includes the reserved word private if:
* the name appears in the visible part of a package or generic
package, or
* the name appears in a use_clause in a context_clause.
makes both C and E illegal, because both appear in the visible part of some
package. In both cases, the items are also in a private part, but that isn't
relevant.
A simple alternative is:
A name shall not denote a declaration mentioned only in a with_clause which
includes the reserved word private if:
* the name appears in the visible part of the package or generic
package on which the with_clause appears, or
* the name appears in a use_clause in a context_clause.
This makes E legal, but not C. That is OK (I wonder if C could be
re-exported later in the visible part of Pack anyway). But this rule has a
fatal flaw: it makes G legal, which we clearly do not want.
We could complicate the rule further by including children explicitly, but
this does not look appealing.
After all, the best reason for making C legal is that if Nest was extracted
and turned into a child package, C would be legal. This seems like the
preferred property (assuming that there isn't a way to re-export the private
information).
Tucker then goes on to propose (OK, I'm writing the wording for him):
A name denoting a declaration mentioned only in a with_clause which
includes the reserved word private shall appear only in the context_clauses,
private part, body, or descendants of the package or generic package on which
the with_clause appears. Such a name shall not appear in a use_clause in a
context_clause.
(I added "context_clause" here, so that the intended uses of the name for
further private withs and in Elaborate pragmas are allowed).
This makes C illegal (because a nested package is not a descendant) and E is
legal (because it is in the private part. However, G is now legal (because
Pack.Child is a descendant of the package), so this wording does not work.
To fix these problems, we need to make two changes to this wording. First,
we need to avoid specifying which package. Any package in the scope of the
with clause qualifies, and should have the same rules applied. Secondly, we
don't need the descendant wording for child packages, because they are
already covered. We do need to cover subunits and child subprogram bodies.
(We don't allow use of these items in subprogram specifications.) That is
easy, however, because both are bodies.
So let's try:
A name denoting a declaration mentioned only in a with_clause which
includes the reserved word private shall appear only in a context_clause,
body, or private part of a package or generic package. Such a name
shall not appear in a use_clause in a context_clause.
"Body" here is the syntactic "body". We could also use "proper_body" here
(as there is no need to include stubs here, they will always be in a body
themselves).
This makes C, D, E, F, and H legal, and A, B, and G illegal. Which is what
we want. It also allows the use of the name in subunits (which are always
proper_bodys) and in the body of child subprograms. We eliminate making any
package special, so changing nested packages to child packages or vice versa
works without change. And the name works in any body in which it is in
scope, which as it should be.
This has one minor glitch, in that it doesn't allow use in the visible part
of a private child of the unit. Fixing that:
A name denoting a declaration mentioned only in a with_clause which
includes the reserved word private shall appear only in a context_clause,
body, private part of a package or generic package, or private descendant of
the unit on which the with_clause appears. Such a name shall not appear in
a use_clause in a context_clause.
I'm not quite sure this last is worth it, but it seems necessary for
consistency.
I'm no fan an enumerating the legal places for a rule, because it is easy to
forget one. But this seems to be the correct solution to me.
Tuck's "visible place" wording really doesn't simplify this much (if at
all), it just lets us describe the illegal places. And I'm not quite sure
how it would work - my first question is "visible to what"? And we'd still
need the context_clause exceptions. So I don't think that is worth it.
I've updated the AI with this wording; we can discuss it at the meeting or
via mail.
****************************************************************
From: Robert Dewar
Sent: Saturday, December 21, 2002 1:33 PM
> That would prevent using type stubs in private parts. One of the big
> advantages of type stubs over the original "with type" is that type stubs
> can be made to be private. That let's you declare a handle to them without
> exposing the actual access type to the world:
Incidentally, I find it a serious flaw that there is no separate context
clause for the private part (for my programming, a much more serious flaw
than the concern about mutually recursive types). Is this issue being
addressed at all.
****************************************************************
From: Randy Brukardt
Sent: Saturday, December 21, 2002 2:36 PM
That's the point of the "private with" clause, see AI-262, already approved
by WG9. A fine candidate for a trial implementation in my view. :-)
****************************************************************
From: Robert Dewar
Sent: Saturday, December 21, 2002 2:42 PM
Ah yes, sorry, forgot about that. Indeed that is indeed a fine candidate
for trial implementation. What we are planning to do in GNAT is to have
the private part in a separate file, and then that file is where the
private with's would go.
We constantly find it annoying both from an IPR point of view and multiple
implementation point of view to have the private part in the same file as
the spec. For one thing it leads to IPR statements like:
-- This specification is derived from the Ada Reference Manual for use with --
-- GNAT. The copyright notice above, and the license provisions that follow --
-- apply solely to the contents of the part following the private keyword. --
:-)
And indeed I agree that a variant of this is needed for the type stubs case.
****************************************************************
From: David Emery
Sent: Saturday, December 21, 2002 3:09 PM
Given the intended use of Java, I'm amazed that this isn't a bigger problem
in that community. If I were king, the first thing I'd add to Java is
named parameter notation. Pure syntactic sugar with tremendous benefits
for readability and maintainability. Separate specs and bodies would be
#2 on my list, followed by enumeration types, strongly typed scalars, and
finally some way to raise the level of the concurrency primitives to that
approaching Ada95...
****************************************************************
From: Robert A. Duff
Sent: Saturday, December 21, 2002 3:42 PM
> We constantly find it annoying both from an IPR point of view and multiple
> implementation point of view to have the private part in the same file as
> the spec.
I agree.
What will the syntax look like?
****************************************************************
From: Robert Dewar
Sent: Saturday, December 21, 2002 3:52 PM
Haven't decided yet. Note that we can choose any "syntax" we like because
tehcnically it is merely a source representation issue (i.e. we have a funny
source representation for private parts, which is our way of representing
the standard syntax).
****************************************************************
From: Robert A. Duff
Sent: Saturday, December 21, 2002 4:32 PM
The "obvious" thing would be to split the text just before "private",
so one file would have:
with Something;
private with Something_Else;
package P is
type T is private;
procedure Mumble(X: T; Y: Something.T);
and the other file would have:
private
type T is new Something_Else.Whatever;
end P;
But that's pretty ugly:
- The "private with" really ought to be in the second file.
- The lack of "end" in the first file looks silly.
- There ought to be a way for the reader of the first file to know
whether the second one exists.
- The second file ought to have the package name near the beginning,
rather than just on the "end" line.
To honestly claim "merely a source representation issue", I think you
have to specify an automatable way of translating to the "real" syntax.
Preferably, a *simple* translation.
I wonder if we could arrive at an agreement on this "source rep" that
could be implemented in all the compilers? The ARG need not be
officially involved, since it's "merely a source representation issue".
It seems trivial to implement. And if we all do it the same way, that's
good for Ada, and what's good for Ada is good for all Ada vendors...
(I like to think that our competition is other languages, not other Ada
compiler vendors...)
It seems obvious (with 20-20 hindsight) that the private part ought to
be in a separate file from the visible part. Too bad the syntax was not
originally designed with this in mind.
Another issue that comes to mind is that if the visible part of a
library package has nested packages/tasks/protected types, then it would
be desirable to move those nested private parts into the second file,
too.
****************************************************************
From: Robert Dewar
Sent: Saturday, December 21, 2002 5:16 PM
> To honestly claim "merely a source representation issue", I think you
> have to specify an automatable way of translating to the "real" syntax.
> Preferably, a *simple* translation.
Sure, but all the glithces you mention are easily corrected under these
criteria.
> I wonder if we could arrive at an agreement on this "source rep" that
> could be implemented in all the compilers? The ARG need not be
> officially involved, since it's "merely a source representation issue".
> It seems trivial to implement. And if we all do it the same way, that's
> good for Ada, and what's good for Ada is good for all Ada vendors...
> (I like to think that our competition is other languages, not other Ada
> compiler vendors...)
I think that would be nice (to agree on this format).
> Another issue that comes to mind is that if the visible part of a
> library package has nested packages/tasks/protected types, then it would
> be desirable to move those nested private parts into the second file,
> too.
I think that's over complex over kill :-)
****************************************************************
From: Tucker Taft
Sent: Saturday, December 21, 2002 12:48 AM
To me, the "obvious" syntax would be something closer to:
package P is
...
private is separate;
end P;
package private P is
....
end P;
The syntax for the separate private part is using "private"
somewhat the way "body" is used.
****************************************************************
From: Robert Dewar
Sent: Sunday, December 22, 2002 7:17 AM
That seems fine to me, and is close to one of the forms we had considered
in particular the "private is separate" seems natural. The private with's
also go in the private part file of course.
****************************************************************
From: Dan Eilers
Sent: Monday, December 23, 2002 11:44 AM
Robert Dewar wrote:
> >
> > That's the point of the "private with" clause, see AI-262, already approved
> > by WG9. A fine candidate for a trial implementation in my view. :-)
>
> Ah yes, sorry, forgot about that. Indeed that is indeed a fine candidate
> for trial implementation. What we are planning to do in GNAT is to have
> the private part in a separate file, and then that file is where the
> private with's would go.
I believe that AI-262 as written is not particularly conducive to
shuffling the private with's to a separate file, since the private with's
have semantic effect (albeit minor) in the visible part of the package.
If ACT seriously intends to implement private parts in a separate file,
then other vendors would likely do so as well, making private with's
of AI 262 a deprecated feature.
My understanding is that the premise of AI 262 and AI 217 is that it is
too much implementation burden to support breaking a package spec into
separate files, each with their own context clause. If this is really
not the case, then AI 217 should probably be solved by breaking the
visible part of a package into separate files, each with their own
context clause, consistent with the ACT plan for separate private parts.
****************************************************************
From: Robert Dewar
Sent: Monday, December 23, 2002 11:53 AM
> I believe that AI-262 as written is not particularly conducive to
> shuffling the private with's to a separate file, since the private with's
> have semantic effect (albeit minor) in the visible part of the package.
>
> If ACT seriously intends to implement private parts in a separate file,
> then other vendors would likely do so as well, making private with's
> of AI 262 a deprecated feature.
This is confused. Putting these in a separate file is simply a matter of
source representation, it has no effect whatever on the semantics as far
as I am concerned. In other words, the parser reassembles the canonical
file from the two parts before anything else happens (note that indeed we
can in practice put perfectly ordinary with's in the private part file, but
it's neater with the private with).
> My understanding is that the premise of AI 262 and AI 217 is that it is
> too much implementation burden to support breaking a package spec into
> separate files, each with their own context clause. If this is really
> not the case, then AI 217 should probably be solved by breaking the
> visible part of a package into separate files, each with their own
> context clause, consistent with the ACT plan for separate private parts.
This seems confused. Files are an implementation artifact, there is no such
concept in the RM.
****************************************************************
From: Robert A. Duff
Sent: Monday, December 23, 2002 12:06 PM
> I believe that AI-262 as written is not particularly conducive to
> shuffling the private with's to a separate file, since the private with's
> have semantic effect (albeit minor) in the visible part of the package.
I don't think it's a big deal. You have to run the parser on *both*
files before doing semantic analysis on them. After parsing both,
analyze the with clauses from the visible-part file, then the with
clauses from the private-part file, then the rest of the vis part,
then the rest of the private part. A bit odd, perhaps, but not hard to
implement.
It seems important that splitting a package spec into two files should
not change its semantics.
****************************************************************
From: Robert Dewar
Sent: Monday, December 23, 2002 12:11 PM
Exactly, and indeed likely our initial implementation will just use normal
with clauses, since we have not bothered with private with yet, and have
no plans to do so in the near future.
****************************************************************
From: Dan Eilers
Sent: Monday, December 23, 2002 12:16 PM
> This is confused. Putting these in a separate file is simply a matter of
> source representation, it has no effect whatever on the semantics as far
> as I am concerned. In other words, the parser reassembles the canonical
> file from the two parts before anything else happens (note that indeed we
> can in practice put perfectly ordinary with's in the private part file, but
> it's neater with the private with).
It sounds like you intend to restrict the with clauses on the private part
of package A from depending on a unit B that in turn depends on A. But
this seems to be an unnececessary restriction. Certainly the with clauses
allowed on subunits don't have such a restriction.
The intent of implementation freedom of source representation is not for
purposes such as this. Abusing this implementation freedom creates
unportable code.
****************************************************************
From: Robert Dewar
Sent: Monday, December 23, 2002 12:32 PM
> > It sounds like you intend to restrict the with clauses on the private part
> > of package A from depending on a unit B that in turn depends on A. But
> > this seems to be an unnececessary restriction. Certainly the with clauses
> > allowed on subunits don't have such a restriction.
No, we do not intend any such restrictions, this is simply a matter of
lexical separation of IPR concerns, and also to help with separation of
target dependent private parts, nothing more, nothing less. Yes, you can
propose something fancier. I am not sure it is worth it.
> The intent of implementation freedom of source representation is not for
> purposes such as this. Abusing this implementation freedom creates
> unportable code.
No more unportable than putting multiple units in a single file. In either
case you need a (trivial) tool to convert from one form to the other for
export. GNAT for instance cannot digest multiple units in one file (which
is of course *purely* a source representation issue) and has a tool to
split incoming non-portable code from other compilers :-)
****************************************************************
From: Dan Eilers
Sent: Monday, December 23, 2002 1:06 PM
This seems confused. If the private part of A depends on B which depends
on A, then the resulting transformation using "private with" would not be
legal due to circularity between package specs.
package A is
...1
private is separate;
end A;
with A;
package B is
...2
end B;
with B;
package private A is
...3
end A;
presumably transforms to:
private with B; -- illegal circularity
package A is
...1
private
...3
end A;
with A;
package B is
...2
end B;
****************************************************************
From: Robert Dewar
Sent: Monday, December 23, 2002 1:16 PM
no that's not the transformation, if you use a with clause, it would
transform to a with clause.
Please understand, the separation of canonical represeantation, whose
syntax and semantics is well understood into two files is a purely lexical
issue, the two files get reassembled into canonical form before they are
processed.
****************************************************************
From: Robert A. Duff
Sent: Monday, December 23, 2002 1:10 PM
Dan said:
> > > It sounds like you intend to restrict the with clauses on the private part
> > > of package A from depending on a unit B that in turn depends on A. But
> > > this seems to be an unnececessary restriction. Certainly the with clauses
> > > allowed on subunits don't have such a restriction.
And Robert replied:
> No, we do not intend any such restrictions,
I think Dan is correct in the first sentence: you *do* intend such a
restriction, since such a restriction already exists in Ada, and your
intent is a "mere" source-rep thing, not a change in semantics.
Dan is talking about package-spec A with's B, and package-spec B with's
A. Surely that will still be an illegal circle, even if the with's
appear in the private-part file.
Am I missing something? It seems to me that to claim "source rep",
then a with appearing in the private-part file must behave identically
to one appearing in the visible part file (because conceptually, that
transformation is exactly what happens).
If private parts have their own dependences, separately from the visible
part, then that would imply that something else can be elaborated in
between the visible and private parts. I suspect that would break
things badly. The freezing rules, for example, depend on the whole
package spec being elaborated at once.
I don't think Dan's reference to subunits is relevant: subunits can
appear only in bodies, and with-clauses only refer to specs. So moving
a with clause from a subunit to its parent body cannot introduce a
cyclic dependence on that *body*.
>... this is simply a matter of
> lexical separation of IPR concerns, and also to help with separation of
> target dependent private parts, nothing more, nothing less. Yes, you can
> propose something fancier. I am not sure it is worth it.
>
> > The intent of implementation freedom of source representation is not for
> > purposes such as this. Abusing this implementation freedom creates
> > unportable code.
I agree with Dan here. But I was hoping to get an informal agreement
among compiler writers to support the same way of visible/private
splitting.
> No more unportable than putting multiple units in a single file.
Yeah, that also leads to unportable code. I think it's unfortunate that
all compilers don't agree on this point.
>...In either
> case you need a (trivial) tool to convert from one form to the other for
> export. GNAT for instance cannot digest multiple units in one file (which
> is of course *purely* a source representation issue) and has a tool to
> split incoming non-portable code from other compilers :-)
Right, GNAT is not in violation of the "law" here, but it's still a pain
to have to use extra tools. In practice, it's much better to use the
lowest common denominator supported by all compilers, than to use tools
to translate from one form to another.
In particular, I wouldn't use separate files for private parts unless I
had some confidence that most or all compilers would support that
representation. Even though it is indeed useful to have that physical
separation.
****************************************************************
From: Robert Dewar
Sent: Monday, December 23, 2002 1:18 PM
> I think Dan is correct in the first sentence: you *do* intend such a
> restriction, since such a restriction already exists in Ada, and your
> intent is a "mere" source-rep thing, not a change in semantics.
What I meant is that there are no additional restrictions of any kind that
come from the splitting into two files, this is simply a lexical issue.
> Yeah, that also leads to unportable code. I think it's unfortunate that
> all compilers don't agree on this point.
Since the standard has nothing whatever to say in this area, why does it
surprise you. The standard is not in the business of specifying source
represaentation and never has been.
****************************************************************
From: Dan Eilers
Sent: Monday, December 23, 2002 1:45 PM
Robert Duff wrote:
> If private parts have their own dependences, separately from the visible
> part, then that would imply that something else can be elaborated in
> between the visible and private parts. I suspect that would break
> things badly. The freezing rules, for example, depend on the whole
> package spec being elaborated at once.
My suspicion is that it would hardly break things at all, and users would
insist on eliminating the silly restriction. Depending on a private type
before its full type has been seen would be exactly like depending on a
type stub.
****************************************************************
From: Robert A. Duff
Sent: Monday, December 23, 2002 2:47 PM
> My suspicion is that it would hardly break things at all, and users would
> insist on eliminating the silly restriction. Depending on a private type
> before its full type has been seen would be exactly like depending on a
> type stub.
package A is
C: constant String;
private is separate;
end A;
with A;
package B is
X: String := A.C;
end B;
private with B; -- Illegal cycle!
package private A is
C: constant String := X;
end A;
It's not clear what the run-time semantics of the above ought to be.
I claim it should be illegal (and it *is* illegal, if you go the
route that Robert has been advocating).
****************************************************************
From: Robert Dewar
Sent: Monday, December 23, 2002 3:08 PM
This most certainly should be illegal. I do not know what it might be
intended to mean if it were legal!
****************************************************************
From: Dan Eilers
Sent: Monday, December 23, 2002 3:11 PM
I agree that it should be illegal, but maybe for different reasons.
The declaration of B.X should be illegal as an unallowed use of
a deferred constant, just as it would be illegal to say:
package A is
C: constant String;
X: String := A.C;
private
C: constant String := X;
end A;
Note: in this example, there is only one possible compilation order,
so it is pretty clear that package B is intended to depend only on the
visible part of A. However, that wouldn't always be true in general,
so we would need to provide some way to indicate that a with clause is
intended to apply only to a package's visible part. Otherwise there
would be cases where legality depended on compilation order.
****************************************************************
From: Robert A. Duff
Sent: Monday, December 23, 2002 3:10 PM
> > I think Dan is correct in the first sentence: you *do* intend such a
> > restriction, since such a restriction already exists in Ada, and your
> > intent is a "mere" source-rep thing, not a change in semantics.
>
> What I meant is that there are no additional restrictions of any kind that
> come from the splitting into two files, this is simply a lexical issue.
Dan was suggesting to *remove* an existing restriction, not to add an
additional one. Removing restrictions is bad, because it removes the
pure lexical nature of the transformation.
However, I think there *should* be an additional restriction: If you say
"with X;" in a private part file, you should not be allowed to refer to
X in the visible part. Otherwise, you've defeated the whole readability
purpose of having with clauses at the front.
Note that you objected to type stubs for the same reason -- you don't
like referring to some other package without having a with clause up
front.
> > Yeah, that also leads to unportable code. I think it's unfortunate that
> > all compilers don't agree on this point.
>
> Since the standard has nothing whatever to say in this area, why does it
> surprise you. The standard is not in the business of specifying source
> represaentation and never has been.
It doesn't surprise me; it annoys me. My point is that the world would
be a better place if all Ada compilers supported the same source
representations (including how many comp units you can put in a file,
file-naming conventions, etc). I know full well that this is not an RM
issue.
****************************************************************
From: Robert Dewar
Sent: Monday, December 23, 2002 4:16 PM
That ups the ante in the difficulty of implementation considerably. I
perfectly well understand that it would be nice-to-have :-)
****************************************************************
From: Robert A. Duff
Sent: Monday, December 23, 2002 4:36 PM
Robert wrote:
> That ups the ante in the difficulty of implementation considerably.
Agreed. It's essentially the same as implementing "private with".
In fact, the obvious thing is to say that "private with"s go in the
private-part file.
If it's too much trouble to implement this "properly", at least
documentation ought to admonish programmers to be careful.
> ...I perfectly well understand that it would be nice-to-have :-)
Agreed.
****************************************************************
From: Randy Brukardt
Sent: Friday, January 17, 2003 5:38 PM
Replying to an old conversation of Bob and Robert's that happened while I
was away at Christmas:
Bob replying to Robert replying to Bob:
>>> However, I think there *should* be an additional restriction: If you say
>>> "with X;" in a private part file, you should not be allowed to refer to
>>> X in the visible part. Otherwise, you've defeated the whole readability
>>> purpose of having with clauses at the front.
>>>
>>> Note that you objected to type stubs for the same reason -- you don't
>>> like referring to some other package without having a with clause up
>>> front.
>>That ups the ante in the difficulty of implementation considerably. I
>>perfectly well understand that it would be nice-to-have :-)
>> Agreed. It's essentially the same as implementing "private with".
>> In fact, the obvious thing is to say that "private with"s go in the
>> private-part file.
Well, actually, the obvious thing to say is that any "with"s in the private
part file are transformed to "private with"s in the transformed file.
Indeed, I can hardly imagine why you would want any other semantics - you
certainly don't want withs used in the spec that aren't even on the source.
Now, of course, if some compiler hasn't implemented "private with" yet, then
there is no real difference. But that shouldn't matter to the
"transformation" that is behind this. Particularly if we want to agree on it
as a quasi-standard.
> If it's too much trouble to implement this "properly", at least
> documentation ought to admonish programmers to be careful.
"private with" is supposed to be dirt-cheap to implement. Because the only
effect is that certain references are illegal (all other things remaining
the same, including the visibility of the illegal references), it seems only
to require a symboltable bit for package declarations, a function to
determine if the current locality of a reference is not in a private part
(that is, the rules in AI), and an error message. The function might be a
bit messy in some implementations, but I doubt it could be too bad; there's
plenty of other places where you need to figure out whether you're in a
visible or private part. This shouldn't be more than a few days work,
including documentation. The separate private part mechanism would be at
least as much work (most of it going to the tool to create the canonical
representation, which has to be able to lex Ada source and do at least
limited parsing). So I don't see much reason to avoid implementing it if
you're going to going through the greater effort of the separate
compilation.
****************************************************************
!topic "private with" and generic formal parameters
!reference RM05-10.1.2
!from Duncan Sands 05-05-20
!discussion
Is the following construction intended to be legal?
-- G --
generic
with procedure E;
package G is
pragma Elaborate_Body; -- E not used in public part
end;
package body G is
... -- E used in body
end;
-- P --
package P is
...
end;
-- P.E --
private procedure P.E;
procedure P.E is
...
end;
-- P.C --
with G;
private with P.E;
package P.C is new G (P.E); -- is this declaration legal?
****************************************************************
From: Gary Dismukes
Sent: Friday, May 20, 2005 3:47 PM
> with G;
> private with P.E;
> package P.C is new G (P.E); -- is this declaration legal?
No, the instantiation is illegal because the name of a privately
withed unit isn't allowed in that context (basically it's only
allowed within private parts and bodies). It would be unlikely
to be a simple change to allow this since special rules would
be required to prevent incorrect uses, plus the visibility rules
don't come into play in the implicit specification of a generic
instantiation.
****************************************************************
From: Duncan Sands
Sent: Thursday, June 2, 2005 10:25 AM
I agree that it looks like more trouble than it is worth. This
came up when I wanted to pass a lock into the body of a generic
package, without the lock being publicly visible. It was easy
enough to get the same effect by putting a wrapper around the
generic. So personally I have no use for this construction, but
I thought I should bring it up since I saw no discussion in the
AI.
****************************************************************
From: Tucker Taft
Sent: Tuesday, January 3, 2006 7:25 AM
It seems somewhat weird that we disallow limited
withs appearing on a body, but we allow private
withs to appear there. It would seem more appropriate
to allow both private withs and limited withs only
on (generic) package specs. Having a private with
on a body implies the user is pretty confused.
I noticed this while reviewing John Barnes update
to his "Programming in Ada" text book.
****************************************************************
From: Robert Dewar
Sent: Tuesday, January 3, 2006 7:50 AM
It's a bit strange, but I would not make this change at this late date.
****************************************************************
From: Pascal Leroy
Sent: Wednesday, January 4, 2006 3:08 AM
Read The Funny Minutes.
The minutes of the Vienna meeting show that this was discussed, and that
the justification for allowing "private with" everywhere was that it would
simplify automatically generated code. There was a clear consensus on
this decision: the straw poll was 7-0-1.
It seems to me that the analogy that you draw between "limited with" and
"private with" is misguided. Despite the syntactic similarity, the two
are very different beasts: "private with" gives you normal visibility,
albeit in a restricted region; "limited with" gives you a very strange
kind of visibility. So it's not surprising that there are differences
between the two.
This is certainly insufficiently broken. In fact, I am not sure it is
broken at all...
****************************************************************
From: John Barnes
Sent: Wednesday, January 4, 2006 8:28 AM
When writing the rationale (and my book), I found it quite natural that a
private with could go on a body. What I do now find strange is that a
private with on a body cannot be accompanied by a use clause thus
private with Q; use Q; -- illegal
package body P is ..
I can sort of understand the restriction on a spec because a reader might
feel that the use clause would apply to the visible part (How about private
use Q; ?? No John don't make silly suggestions at this stage).
It is OK I think.
****************************************************************
Questions? Ask the ACAA Technical Agent