!standard 10.01.02 (04) 02-05-10 AI95-00262/04 !standard 10.01.02 (08) !class amendment 01-02-15 !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" makes a unit available only in the private 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, and the with_clause shall include the reserved word private. Add after 10.1.2(8): 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. A with_clause which includes the reserved word private shall appear only in the context_clause of a package_declaration or generic_package_declaration. !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; -- (1) private V2 : Integer := B; -- (2) 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. 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 only on (generic) package specifications. This avoids confusion as to the meaning of them on bodies and subprogram specifications. We could allow them on bodies, but they would have to be equivalent to regular withs. For subprograms, they could be defined to not have an effect in the subprogram specification (useful on subprogram bodies), but this is of limited value. Ada allows a unit to be withed multiple times in a single context clause. In order to handle this, we have proposed that 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. !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 private part of the public 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) @drepl @xindent @iunit_name {, @iunit_name}> @dby @xindent] @b @iunit_name {, @iunit_name}> !corrigendum 10.1.2(08) @drepl If a @fa of a given @fa mentions a private child of some library unit, then the given @fa 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. @dby If a @fa of a given @fa mentions a private child of some library unit, then the given @fa shall be one of: @xbullet @xbullet @xbullet shall include the reserved keyword @b.> A @fa denoting a declaration mentioned only in a @fa which includes the reserved keyword @b shall appear only in a @fa, @fa, private part of a package or generic package, or private descendant of the unit on which the @fa appears. Such a @fa shall not appear in a @fa in a @fa. A @fa which includes the reserved keyword @b shall appear only in the @fa of a @fa or @fa. !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 <> 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: package is private is separate; end ; separate () package private is end ; 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: > > > package is > > private is separate; > end ; > > > separate () > package private is > > end ; 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: package is end ; package private is end ; 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: > > > package is > > end ; > > > package private is > > end ; > > 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 (Discrim : Integer); -- Deferred to body. type Priv(Discrim : Integer) is access (Discrim); Null_Priv : constant Priv in body := ; 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 (Discrim : Integer); -- Deferred to body. > type Priv(Discrim : Integer) is access (Discrim); > Null_Priv : constant Priv in body := ; > > 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 <> 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. <> 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 <> 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 <> 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 <> 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 <> 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 > < 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. > < 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 <> 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 <> Yes, that's my meaninvg of the pragma. Otherwise it is dubious indeed. <> Yes indeed. <> 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 > < 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 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 <> A reasonable rule :-) <> 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. ****************************************************************