Version 1.2 of ais/ai-00262.txt

Unformatted version of ais/ai-00262.txt version 1.2
Other versions for file ais/ai-00262.txt

!standard 13.13.2 (31)          01-02-15 AI95-00262/01
!standard 13.13.2 (34)
!class amendment 01-02-15
!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
!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 used 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 used in the private part of a public package.
!proposal
(* Either "with private", or a separate compilation scheme for private parts; see appendix for rough proposals of each *)
!discussion
!example
!ACATS test
!appendix

From: Randy Brukardt [Randy@RRSoftware.Com]
Sent: Wednesday, February 14, 2001 1:54 PM

A recent discussion on comp.lang.ada proposed a "with private" context
clause, which would allow the withed entity to be used only in the private
part of a package.

The primary benefit of such a feature is that it would allow the use of
private packages in the private part of a public package. This is currently
impossible, and it forces reorganization of packages.

For instance, originally in Claw we put the low-level Win32 interface in a
series of private packages. However, these packages cannot be accessed in
the private part of the public types. That means that either we had to avoid
strong typing in the low-level interface, or abandon the private package
structure.

For instance, a possible image list package would look like:

    package Claw.Low_Level_Image_Lists is
        type HImage_List is new DWord;
        type IL_Flags is new UInt;
        ILR_DEFAULTCOLOR : constant IL_Flags := 16#0000#;
        ILR_MONOCHROME   : constant IL_Flags := 16#0001#;
         ...
        type Image_Kind_Type is (Bitmap, Icon, Cursor);
        for Image_Kind_Type use (Bitmap => 0, Icon => 1, Cursor => 2);

        function Image_List_Load_Image (
                  Name     : in Claw.Win32.LPCStr;
                  Width    : in Claw.Int;
                  Image_Kind : in Image_Kind_Type;
                  Flags    : in IL_Flags) return HImage_List;
        pragma Import (StdCall, Image_List_Load_Image,
                  "ImageList_LoadImageA");

          ...
    end Claw.Low_Level_Image_Lists;

    with Claw.Low_Level_Image_Lists; -- Illegal!
    package Claw.Image_List is
       type Image_List_Type is tagged private;
       procedure Load_Image (Image_List : in out Image_List_Type;
                             Image : in String;
			     Monochrome : in Boolean := False);
         ...
    private
       type Image_List_Type is tagged record
	Handle : Claw.Low_Level_Image_Lists.HImage_List;
            Flags : Claw.Low_Level_Image_Lists.IL_Flags;
              ...
       end record;
    end Claw.Image_List;

We ended up moving things to the private part of the parent (Claw) [which
makes it very large], eliminating some of the strong typing (since users
don't access this code, it only makes our job harder), and not bothering
with the private packages in the first place (putting the entire contents
into the private part of the Image_List package; but of course that mixes up
the high-level and low-level code).

----

I haven't yet looked at the visibility ramifications of such a feature, but
I will do so if there is sufficient interest in working out a full proposal.

****************************************************************

From: dewar@gnat.com
Sent: Wednesday, February 14, 2001 4:50 PM

<<The primary benefit of such a feature is that it would allow the use of
private packages in the private part of a public package. This is currently
impossible, and it forces reorganization of packages.>>

I think it has a much more significant benefit, which is that it makes
it easier to separate the public and private part into separate files,
where the private part has multiple implementations. We have often needed
that capability, and in fact on our enhancement list for GNAT is to allow
the private part to be in a separate file.

****************************************************************

From: Pascal Leroy [pleroy@rational.com]
Sent: Thursday, February 15, 2001 2:01 AM

> A recent discussion on comp.lang.ada proposed a "with private" context
> clause, which would allow the withed entity to be used only in the private
> part of a package.

I agree that this would be a very useful thing to have.  There is another
benefit, in addition to the interaction with private children: by making a
with clause private, you ensure that in the course of maintenance it won't
be used to write declarations in the visible part, i.e., the stuff in the
withed unit won't be reexported.

Moreover, it seems quite easy to (1) specify in RM terms and (2) implement.

A much better usefulness/complexity ratio than extensible enums, if you ask
me.

****************************************************************

From: dewar@gnat.com
Sent: Thursday, February 15, 2001 12:15 PM

I very much agree with this asessment!

****************************************************************

From: Tucker Taft
Sent: Thursday, February 15, 2001 8:57 AM

Randy Brukardt wrote:
>
> A recent discussion on comp.lang.ada proposed a "with private" context
> clause, which would allow the withed entity to be used only in the private
> part of a package.
>
> The primary benefit of such a feature is that it would allow the use of
> private packages in the private part of a public package. This is currently
> impossible, and it forces reorganization of packages.

This is not a trivial change.  Currently, private children are *never*
needed at compile-time of public specs (ignoring macro expansion
requirements related to generics and inlines, of course!).  This
allows a strong physical separation between the public specs and the
"implementation" of a subsystem.  I would be reluctant to see this
principle violated.

In fact, "private" children should more properly be
called "body" children.

>
> For instance, originally in Claw we put the low-level Win32 interface in a
> series of private packages. However, these packages cannot be accessed in
> the private part of the public types. That means that either we had to avoid
> strong typing in the low-level interface, or abandon the private package
> structure.

An alternative structure is to make these *public* packages
but with essentially all of their declarations in the private part.
Is there a reason why this wouldn't work?

>
> For instance, a possible image list package would look like:
>
>     package Claw.Low_Level_Image_Lists is
>         type HImage_List is new DWord;
>         type IL_Flags is new UInt;
>         ILR_DEFAULTCOLOR : constant IL_Flags := 16#0000#;
>         ILR_MONOCHROME   : constant IL_Flags := 16#0001#;
>          ...
>         type Image_Kind_Type is (Bitmap, Icon, Cursor);
>         for Image_Kind_Type use (Bitmap => 0, Icon => 1, Cursor => 2);
>
>         function Image_List_Load_Image (Name     : in Claw.Win32.LPCStr;
>                                         Width    : in Claw.Int;
>                                         Image_Kind : in Image_Kind_Type;
>                                         Flags    : in IL_Flags) return
> HImage_List;
>         pragma Import (StdCall, Image_List_Load_Image,
> "ImageList_LoadImageA");
>
>           ...
>     end Claw.Low_Level_Image_Lists;
>
>     with Claw.Low_Level_Image_Lists; -- Illegal!
>     package Claw.Image_List is
>        type Image_List_Type is tagged private;
>        procedure Load_Image (Image_List : in out Image_List_Type; Image : in
> String;
>                               Monochrome : in Boolean := False);
>          ...
>     private
>        type Image_List_Type is tagged record
>         Handle : Claw.Low_Level_Image_Lists.HImage_List;
>             Flags : Claw.Low_Level_Image_Lists.IL_Flags;
>               ...
>        end record;
>     end Claw.Image_List;
>
> We ended up moving things to the private part of the parent (Claw) [which
> makes it very large], eliminating some of the strong typing (since users
> don't access this code, it only makes our job harder), and not bothering
> with the private packages in the first place (putting the entire contents
> into the private part of the Image_List package; but of course that mixes up
> the high-level and low-level code).

I would think public children with essentially all of their interesting
decls in their private part would help break these big private parts
up.

>
> ----
>
> I haven't yet looked at the visibility ramifications of such a feature, but
> I will do so if there is sufficient interest in working out a full proposal.

****************************************************************

From: Pascal Leroy
Sent: Thursday, February 15, 2001 9:50 AM

> An alternative structure is to make these *public* packages
> but with essentially all of their declarations in the private part.
> Is there a reason why this wouldn't work?

I don't understand this.  Declarations in the private part are not visible
anyway, so what good would it do?  Could you give an example of what you
have in mind?

****************************************************************

From: Randy Brukardt [Randy@RRSoftware.Com]
Sent: Thursday, February 15, 2001 11:49 AM

> An alternative structure is to make these *public* packages
> but with essentially all of their declarations in the private part.
> Is there a reason why this wouldn't work?

Sure, no one would have visibility on the declarations in the private part.
How could you use them?

You must have had something else in mind; could you recast my example as you
suggest?

****************************************************************

From: Tucker Taft
Sent: Thursday, February 15, 2001 12:11 PM

Pascal Leroy wrote:
>
> > An alternative structure is to make these *public* packages
> > but with essentially all of their declarations in the private part.
> > Is there a reason why this wouldn't work?
>
> I don't understand this.  Declarations in the private part are not visible
> anyway, so what good would it do?  Could you give an example of what you
> have in mind?

Good point.  I realize I was misremembering a suggestion
by Robert Eachus.  The "trick" is to have an immediate parent
which has all of its declarations in its private part, and then
use renaming to rename the child so that it is directly beneath
its grandparent.  For example:

    package Claw is
       ...
    end Claw;

    package Claw.Hidden is
      private
         -- lots of private junk
    end Claw.Hidden;

    package Claw.Hidden.Child is
      -- useful stuff
    private
      -- Claw.Hidden private part is visible here
    end Claw.Hidden.Child;

    with Claw.Hidden.Child;
    package Claw.Child renames Claw.Hidden.Child;

Not particularly elegant, but might solve the problem.

****************************************************************

From: Randy Brukardt
Sent: Thursday, February 15, 2001 1:49 PM

Well, Claw has 6 private low-level packages (otherwise, *they* get too
large -- Win32 is huge). Would you like to try this solution for a set of
interrelated private packages?? :-) :-)

This is, after all, essentially what we did to work around this problem: we
declared lots of stuff in the private part of the ultimate parent (Claw),
but the effect is to bloat that package. It doesn't provide a solution, just
a work-around.

****************************************************************

From: Randy Brukardt
Sent: Thursday, February 15, 2001 6:19 PM

We've gotten so fixed on Tucker's silly workaround suggestion that no one
has addressed his real concerns...

> This is not a trivial change.  Currently, private children are *never*
> needed at compile-time of public specs (ignoring macro expansion
> requirements related to generics and inlines, of course!).  This
> allows a strong physical separation between the public specs and the
> "implementation" of a subsystem.  I would be reluctant to see this
> principle violated.
>
> In fact, "private" children should more properly be
> called "body" children.

You are forgetting that the private part of a spec really is part of the
*implementation* of a unit, not part of the specification. So, the current
situation is that part of the implementation can use private units, and part
don't.

If you really want to have this sort of physical separation, we have to have
some way to put private parts in a separate file. That seems like a much
more radical change than "with private" would be.

Given that Robert indicated that ACT was thinking about implementing
something on that line, perhaps it would be worthwhile to engage in a bit of
on-the-fly language design.

Here are my assumptions:

  1) We don't want to change the invariant that the size of an Ada entity is
known once the spec is compiled. Eliminating that would be a massive change
to Ada compilers, and I really doubt that any such idea could get much
support from implementors.
  2) We do want to allow a separate private part have its own context
clause, and allow private units to be withed there.
  3) We need rules that would work both in source-based and "traditional"
compiler structures.
  4) We don't need any additional functionality in the private part other
than (2).

(1) implies that the separate private part must be available when the
specification is compiled. For the "traditional" model, that means either it
must be compiled first (but what could that mean? It could depend on parts
of the spec) or compiled at the same time as the spec. For the
"source-based" model, this means that the source must be available when the
spec is compiled/used.

Assuming that the private part is available when the spec is compiled, the
separate private part would essentially be an "include" file, and shouldn't
cost much additional work in compilers. Most of the work would go into the
functionality of "with private".

Syntax for this seems hard to come up with. The best I can come up with
would be:

    <context_clause>
    package <Name> is
        <public declarations>
    private is separate;
    end <Name>;

    <context clause>
    separate (<Name>)
    package <Name> private is
        <private declarations>
    end <Name>;

Clearly, we would need a rule requiring the separate private to be available
when the spec is compiled -- and that is very different than other
separates, which are "real" separate compilation. We also would need to
extend the permissions in 10.1.4(7) to allow removing the spec from the
library when the private part is "added to the environment".

I guess my primary objection to this idea is that it isn't what it looks
like -- the private part is not really independent of the specification. But
that isn't necessarily a big deal (and different syntax might help here).

Tuck, would a proposal on this line address your objection??

****************************************************************

From: Robert A Duff
Sent: Thursday, February 15, 2001 8:14 PM

Randy suggests:

> Syntax for this seems hard to come up with. The best I can come up with
> would be:
>
>     <context_clause>
>     package <Name> is
>         <public declarations>
>     private is separate;
>     end <Name>;
>
>     <context clause>
>     separate (<Name>)
>     package <Name> private is
>         <private declarations>
>     end <Name>;

If I were designing the language from scratch, I would put the "imports"
(with_clauses) *inside* the thing importing.  And the private part would
be a separate syntactic entity, presumably in a separate file.  Or it
wouldn't exist at all.

But we're stuck with private parts.  Sigh.

I suggest this syntax:

    <context_clause>
    package <Name> is
        <public declarations>
    end <Name>;

    <context clause>
    package <Name> private is
        <private declarations>
    end <Name>;

Presumably, most compilers would require that the private part "exist"
when compiling clients, and when compiling the visible part itself.
No need to make it look like a subunit, IMHO.

****************************************************************

From: Randy Brukardt
Sent: Thursday, February 15, 2001 8:33 PM

> I suggest this syntax:
>
>     <context_clause>
>     package <Name> is
>         <public declarations>
>     end <Name>;
>
>     <context clause>
>     package <Name> private is
>         <private declarations>
>     end <Name>;
>
> Presumably, most compilers would require that the private part "exist"
> when compiling clients, and when compiling the visible part itself.
> No need to make it look like a subunit, IMHO.

The problem with that is that a compiler couldn't tell the difference
between a package spec that has a separate private part, and one that has no
private part at all. We fixed problems like that in Ada 95, I don't think
we'd want to reintroduce them. So there has to be some sort of stub in the
package spec.

****************************************************************

Questions? Ask the ACAA Technical Agent