From: stt@spock.camb.inmet.com (Tucker Taft)
Newsgroups: comp.lang.ada
Subject: Re: private types and recompilation
Date: 28 Jan 93 15:25:46 GMT
Organization: Intermetrics Inc, Cambridge MA

In article <9301271722.aa25516@Paris.ics.uci.edu> 
  kanderso@mabillon.ICS.UCI.EDU (Kenneth Anderson) writes:

>In comp.lang.ada you write:
>
>>When Ada 83 was designed, why did the designers choose to put
>>the details of private types in package specifications, rather than
>>in package bodies (which is more in the spirit of information hiding, and
>>better supports independent compilation).
>
>I'm not sure, but I think because the compiler needs to know the size
>of the types so that it can allocate space for parameters in the
>subprograms that are defined in the spec.

Parameters are not a great problem, because they can in general
be passed by reference (though if the full type is a scalar or
access type, pass by copy is required).  However, to be able
to allocate local variables of a private type outside the
defining package, and to implement the "=" operator and ":=" operation
correctly, some knowledge of the representation is required.
It is possible to defer all of this to link-time, but for languages
like Ada (and C++, by the way), the choice was made in favor
of minimizing run-time overhead, at the expense of more recompilation.

A general principle in Ada is that every abstraction has
a "logical interface" (the visible part), a "physical interface" (the
private part), and an "implementation" (the body).
If you don't change the logical interface, then you don't have
to edit the source of the clients.  If you don't change the
physical interface, then you don't have to recompile the clients;
only relink.

This principle of separation is carried out quite consistently 
throughout the language, and has been maintained (and somewhat
enhanced with private child packages) in Ada 9X.

As far as the official rationale, here is a paragraph from
the '86 Rationale for the Design of the Ada Programming Language
(section 9.3.3 "Influence of Separate Compilation on the
Design of Packages," page 183):

    The declaration of a private type therefore does not in itself
    provide enough information for storage allocation and other
    operations.  The full declaration of the type is needed, and so
    is any representation clause that the user wants: storage allocation
    will therefore require the information provided by the private part.
    Note that placing this information in the package body would not
    be satisfactory since it would create unnecessary dependences of
    other compilation units on this body, with the consequence that
    changes in the algorithms provided in the body would require
    recompilation of these other compilation units, even in the
    absence of change to the full type declaration.

As a relatively late change to Ada 83, the rules for "incomplete"
types were relaxed somewhat, so that if a private type was
in fact an access type, then the full definition of its designated
type could be deferred into the package body, as mentioned
in the response by Ken Anderson:
  
>>generic
>>  type ATOM is private;
>>package LIST_ADT is
>>  type POSITION is private;
>>  type LIST is private;
>>  procedure CREATE(L: in out LIST);
>>  procedure INSERT_AFTER(L: in out LIST; P: POSITION; A: ATOM);
>>  ...
>
>>private
>>  type LIST;
>>  type POSITION is access LIST;
>
>You only need the previous two lines.  The declaration below can be
>hidden in the body of the package.
>
>>  type LIST is record
>>    A: ATOM;
>>    NEXT: POSITION;
>>  end record;
>>end LIST_ADT;
>
>
>>-Dave Erickson
>
>Ken

By the way, in Ada 9X, there is another alternative, namely an
"abstract tagged type."  Such a type (say, "T") can be used as the root 
of a hierarchy of (tagged) types, and the corresponding "class-wide 
type" (T'CLASS) can be used as the type of a subprogram formal parameter, 
allowing algorithms to be written that have no knowledge of the
reprsentation of the various derivatives of the abstract type.

Such "class-wide" algorithms work by relying strictly 
on the "primitive" operations of the abstract type.
Parameters of a class-wide type are naturally passed by reference,
and calls on the primitive operations of such a type are dynamically 
bound to the appropriate operation, based on a "tag" that identifies
the specific type of the actual object associated with the given formal
parameter.  It is interesting to note that the '86 Rationale foreshadowed
this capability (quoting from earlier in section 9.3.3):

    ...  A more flexible architecture -- evolved perhaps from today's
    "tagged architectures" -- would indeed allow data representation
    choices to be deferred until link time, or even later.

S. Tucker Taft    stt@inmet.com
Ada 9X Mapping/Revision Team
Intermetrics, Inc.
Cambridge, MA  02138
Newsgroups: comp.lang.ada