Version 1.6 of ais/ai-40217.txt

Unformatted version of ais/ai-40217.txt version 1.6
Other versions for file ais/ai-40217.txt

!standard 03.10.01 (02)          03-03-18 AI95-00217-05/02
!standard 03.10.01 (03)
!standard 03.10.01 (04)
!standard 03.10.01 (05)
!standard 03.10.01 (08)
!standard 03.10.01 (09)
!standard 03.10.01 (10)
!standard 03.10.01 (11)
!standard 10.01.02 (03)
!standard 10.01.02 (04)
!standard 10.01.02 (08)
!standard 10.02 (04)
!standard J.11 (00)
!class amendment 03-01-16
!status No Action (10-0-0) 03-10-03
!status work item 03-01-16
!status received 03-01-16
!priority Medium
!difficulty Hard
!subject Type stubs with limited context clauses
!summary
A pair of new constructs, called "type stub"s and "limited with clause"s are added to the Standard to provide a solution to the "mutually recursive types across packages" problem.
A limited with clause makes a compilation unit available for limited use. Some details of such a unit can be used in the current compilation unit without creating a semantic dependence.
A type stub is a kind of incomplete type declaration which is completed in a package specified by a limited with. Compile-time checks are performed on use of the name introduced by the type stub that the completion is "available" and "appropriate" (see !proposal for details).
!problem
Ada allows mutually recursive types to be declared only if they are all declared within the same library unit. This can force all of the major data structures of a program into a single library unit, which is clearly undesirable in some situations.
The goal of the proposed features is to allow mutual recursion among separately compiled types (types containing (pointers to) each other as components, and primitive operations with (pointers to) each other as parameters), and to do this in a way that doesn't place any undue restrictions on the programmer.
!proposal
The syntax for a context_item is amended as follows:
context_item ::= with_clause | use_clause | limited_with_clause limited_with_clause ::= [private] limited with limited_unit_specifier; limited_unit_specifier ::= identifier | limited_unit_specifier . identifier;
The limited_with_clause does not create a semantic dependence on the specified unit. The specified unit can only be used only in contexts that specifically allow the use of limited_unit_specifiers; this clause do not declare a name that can be generally used. The limited_unit_specifier specifies the full expanded name of a compilation_unit. (It's harmless to allow non-packages here, and we can't check anyway.)
The limited_unit_specifier can be used within the declarative region of the compilation_unit, unless the keyword private appears, in which case it may only be used in private parts and bodies. (This is the same rule as for "private with", see AI-262.)
The unit specified by the limited_with_clause is needed if the compilation unit on which it appears is needed - see 10.2. (This insures that the completion appears in the partition.)
A post-compilation check is made that any unit which has a limited_with_clause is included in the semantic closure of the unit named by the limited_unit_specifier. This includes a check that limited_unit_specifier specifies the full expanded name of a library compilation_unit (starting with a root library unit, and using no renaming declarations). (This allows most checks to be accomplished at the point of completion, and also simplifies the implementation for some compilers.)
The syntax for an incomplete type declaration is amended as follows:
incomplete_type_declaration ::= type defining_identifier [discriminant_part]; | type_stub;
[Note: tagged incomplete types are now defined in AI-326.]
A new kind of incomplete type declaration is added:
type_stub ::= type defining_identifier [discriminant_part] is [ tagged ] separate of limited_unit_specifier . type_identifier;
A type_stub introduces an incomplete type whose completion occurs in the unit identified by the limited_unit_specifier, and whose defining_identifier is type_identifier. The limited_unit_specifier must appear in a limited_with_clause for the compilation_unit. If the word TAGGED appears, the type is a tagged incomplete type (see AI-326). The limited_unit_specifier is not subjected to the name resolution rules at the place of the type_stub.
In order to be a completion, the completing type declaration must be in the visible part of the unit specified by the limited_unit_specifier, must not be an incomplete type declaration, and must satisfy all other rules for incomplete type completion. A check is also made that there is no more than one type stub for the completing type declaration. (These checks can be made in the compilation unit containing the completing type declaration, because any type stubs must be in the semantic closure of the unit by the rule above.) Each type stub that specifies a particular unit must be completed in that unit.
When a name introduced by a type stub is used in a context where a complete type is required (which is described above), a check is made that the usage place is within the immediate scope of the completion, or is within the scope of a with clause that mentions the unit identified by the type stub's limited_unit_specifier.
Deferences of an access-to-incomplete type are allowed in limited additional contexts.
!wording
Replace 3.10.1(2):
incomplete_type_declaration ::= type defining_identifier [discriminant_part]; | type_stub
type_stub ::= type defining_identifier [discriminant_part] is [ tagged ] separate of limited_unit_specifier . type_identifier;
limited_unit_specifier ::= identifier | limited_unit_specifier . identifier;
Modify 3.10.1(3):
An incomplete_type_declaration other than a type_stub requires a completion, which ...
Insert 3.10.1(3.1):
A type_stub includes a limited_unit_specifier which specifies the full expanded name of the compilation unit in which its completing type is expected to occur. [Certain uses (see below) of a name that denotes the type_stub or a value of an access type that designates the type_stub, require that the completing type exist.] For a type_stub, the completing type shall occur in the visible part of the specified unit, and be a type_declaration other than an incomplete_type_declaration; the type_identifier shall be the same as the defining_identifier of the completing type. Each completing type shall have no more than one type_stub.
Modify 3.10.1(4):
Replace all occurrences of "full_type_declaration" with "type_declaration" in the existing sentences, so that a private type (or private extension) can complete a type stub.
Replace 3.10.1(5):
An incomplete_type_declaration defines an "incomplete view" of a type. An incomplete view and the corresponding completing type_declaration define two views of the same type.
The only allowed uses of a name that denotes an incomplete view are as follows:
Replace 3.10.1(10):
If a name that denotes an incomplete view is used in other contexts, the complete view shall be available at the place of use, as defined below:
* If the incomplete view is declared by a type_stub, the complete view is available if
* the place of use of the name is within the immediate scope of the completing type of the type_stub; or
* the place of use is within the scope of a with_clause that mentions the unit [(including a library-level renaming)] specified by the limited_unit_specifier of the type_stub.
* If the incomplete view is not declared by an incomplete_type_declaration that is not a type_stub, its complete view is available throughout the (extended) scope of the completion.
* If the incomplete view is a class-wide type, its complete view is available if the complete view of the root of the class is available.
If the complete view of an incomplete view is available, the complete view is used instead of the incomplete view.
A dereference (implicit or explicit) of a value of an access type whose designated type D is an incomplete view is allowed only in the following contexts:
* in a place where the complete view of D is available (see above);
* in a context where the expected type is E and
o E covers the complete view of D, o E is tagged and covers D, o E covers D'Class or its complete view, or o E'Class covers D or its complete view;
* as the target of an assignment_statement where the type of the value being assigned is V, and V or V'Class is the complete view of D.
Replace 10.01.2(3):
context_item ::= with_clause | use_clause | limited_with_clause
Add after 10.01.2(4):
limited_with_clause ::= [private] limited with limited_unit_specifier;
Add after 10.01.2(8):
The limited_unit_specifier of an limited_with_clause that appears on a library_unit_declaration or library_unit_renaming_declaration may be used in entire declarative region of the declaration, which includes all children and subunits. The limited_unit_specifier of an limited_with_clause that appears on a body may be used in that body, including all subunits.
A limited_unit_specifier defined only in abstract_clauses that include the reserved word private shall be used only within
* a private part, * a body, * a private descendant of the unit on which one of these
limited_with_clauses appear.
Post-compilation rules
The limited_unit_specifier of a limited_with_clause shall specify the full expanded name of a library compilation_unit (starting with a root library unit, and using no renaming declarations). The unit that includes the limited_with_clause in its context_clause shall be included in the semantic closure of the unit specified by the limited_unit_specifier.
Add after 10.02(4):
* If a compilation unit is needed, then so are any compilation units specified by the limited_unit_specifiers in limited_with_clauses of its context_clause;
Add J.11:
J.11 The Class Attribute of Non-tagged Incomplete Types
For the first subtype S of a type T declared by an incomplete_type_declaration that is not tagged and is not a type stub, the following attribute is defined:
S'Class
Denotes the first subtype of the incomplete class-wide type rooted at T. The completion of T shall declare a tagged type. Such an attribute reference shall occur in the same library unit as the incomplete_type_declaration.
!discussion
We considered calling these "separate incomplete types", but we felt it was more consistent to use the term "stub" rather than "separate" to be consistent with the program unit "stub" terminology.
An limited_with_clause does not declare a name. This was done so that we do not have to introduce a "ghost" package in order to explain the presence of this name. We also do not want to be able to use the limited_unit_specifier other than in a stub of some sort (with a type stub being the only kind allowed currently). If it is a name, it could be used in other contexts, requiring the insertion of checks that this is not the case into an implementation.
We considered a variety of other syntaxes for limited_with_clauses. Several syntaxes that don't look like with_clauses. Since a limited_with_clause neither declares a name nor creates a semantic dependence, it doesn't seem that much like a with_clause. Thus, some reviewers preferred a different syntax. Two of the syntaxes considered were:
[private] abstract of P;
which was rejected because describing the model it implied was very awkward, and
[private] use type in P;
which was rejected because it is only one keyword different from "use type", and may cause confusion.
We decided to stick with the familar with_clause syntax, as there are also similarities with regular with clauses:
-- The unit named is needed in the partition; -- Dependencies between units are created.
An alternative syntax using "separate" rather than "limited" was also considered, but that did not seem to have the correct connotation.
There is no particular restriction on where a type stub may occur, unlike the restriction on program unit stubs. In particular, a type stub may occur in a declare block, a subprogram body, or anywhere an incomplete type declaration may occur. Of course, they are generally only useful if used in a place where a separately compiled unit can see the stub as well as the completing package, so putting them in a declare block, or a subprogram body without any program unit stubs, would not be of any great use.
There seem to be two general ways that the problem of mutually recursive types is solved in other languages. One approach is to permit unrestricted forward references. This is the approach adopted by Eiffel, Java, and Smalltalk. The other approach is to require "forward" or "incomplete" declarations, sometimes called "signatures" or "partial revelations." This is generally the approach adopted by Ada, as well as Pascal, Modula, ML, C/C++, etc., and is the approach adopted here for cross-package mutual recursion.
We chose the simple approach of extending a single existing Ada feature, rather than adding a basket of heavy new features to provide the needed capability. This simplifies both the conceptual burden and the implementation cost.
The model of a type stub per se does not add any significant new implementation burden, because it is very similar to the incomplete-deferred-to-body type which Ada 95 already has. The compiler does not need to know the real type involved as long as the usage rules for incomplete types are enforced.
Determining the representation of an access type that designates a type stub could be a problem for some implementations that select the representation of an access type based on the designated type. However, this would be no different than for a type whose completion is deferred to the body. Such implementations must already be able to handle this somehow.
Since an access type that designates a type stub is a normal declaration, representation clauses (for storage pools, for instance) can be used as needed. This eliminates many of the problems found in the "with type" proposal. Note that such an access type can be used normally (including allocators, deallocators, and the like) when the completing type is visible.
The key difference here from the "with type" proposal is that type stubs, and any associated access type declarations, are "real" declarations that can be referenced from other packages. A "with type" clause would have had the same rules of a "with" clause, which means that they would not be visible to other packages. Instead, each package would require its own with type clause, making it harder to share access types, and requiring trickier visibility rules to deal with "incomplete" packages as well as incomplete types.
We introduce the idea of an "incomplete view" in this proposal. By so doing, we eliminate any need to talk about type matching, as there is only one type. Also note that we talk about a "completing type" for a type stub, rather than a completion. This avoids triggering the "hidden from all visibility" rules of 8.3 on type stubs. We don't need these rules for type stubs, as it is not possible for the same name to denote both an incomplete view of a type stub and a complete view (the names are necessarily distinct). This property is not shared by any of the alternative proposals. Note that the "hidden from all visibility" rules cause significant problems with ripple effects (that is, indirect semantic dependence: cases where adding or deleting a context clause item from a distant unit changes the legality of some other compilation unit).
Once we have the notion of an incomplete view, we could go further and make incomplete types first-class types, and thus allow the declaration of subtypes of them. This would be easy to do, but it doesn't seem to have any particular value. As unnecessary changes increase the risk of introducing errors, we did not make this change.
Conceptual and implementation difficulties arise from the question where the type is to be regarded as completed and hence allows for object creation and availability of operations of the type. It is clear that such a place must have a semantic dependence on (the package containing) the completing type. However, to avoid ripple effects (see above), we say that the complete view is only "available" when within the immediate scope of the completing type itself, or the scope of a with clause that mentions the completing unit. This rule is relaxed when the completing type is in the immediate context of the usage (i.e., the incomplete view is used in a context where it matched the complete view).
We considered other rules, such as requiring only semantic dependence (rejected due to the ripple effects), or creating an implicit semantic dependence at the point of a usage where the completion was needed (rejected due to difficulties for some implementations, and loss of visible "documentation" of the dependence).
When the complete view of an incomplete view is available, the complete view is used in place of the incomplete view. This allows all of the operations of the complete view to work as expected. These rules have no effect on "old" incomplete types, as such incomplete views are always "hidden from all visibility". We considered modifying the "hidden from all visibility" rules to handle these cases as well, but the changes needed were substantial, and thus were likely to introduce errors into other parts of the language.
This proposal includes post-compilation rules to insure that the completing type always has any type_stubs in its semantic closure. This makes type stubs slightly harder to use, but insures that we can perform all needed checking on the legality of the completing type when the completing unit is compiled. An additional rule insures that the completing type's unit must be included in the partition. Combined with the requirement that the completing type appear in the appropriate unit, we insure that all stubs are completed.
In addition, we require that there is at most one stub for each completing type. This rule was originally adopted in order to eliminate the need for special type matching rules. However, with the adoption of the "incomplete view" model, we no longer need such rules anyway. We've retained the single stub requirement because it appears to make implementation easier for some implementation. [Note: An earlier draft of this AI said that allowing multiple stubs was necessary in order for type stubs to be usable with generics. If true, the rule should be removed.]
The rule requiring that the completing type always has any type_stubs in its semantic closure could be accused of having a ripple effect. After all, removing a with_clause from some unit could make the partition illegal. We could have used wording requiring the with_clause directly on the unit referenced by the limited_with. However, note that it is the partition as a whole that is illegal, not any particular unit. The unit containing the completing type is perfectly legal as long as the unit with the type_stub and limited_with_clause isn't needed by the partition. Moreover, the binder error message for this error is likely to say "unit P needs a with_clause for unit Q as it has a limited_with_clause for P"; the user will simply add the needed clause and move on. As semantic closure is likely to be easier to check, we require the weaker condition.
This proposal does not allowing type stubs to refer to local or nested completing types. This capability could be added by extending the syntax of type stubs to:
type_stub ::= type defining_identifier [discriminant_part] is [ tagged ] separate of [limited_unit_specifier .] {package_identifier .} type_identifier;
and adding appropriate additional wording. If this is done, "old" incomplete types are usually just a shorthand for a type stub specifying the same unit. (If we allowed completions in private parts and bodies, this would be complete.)
This was not done for multiple reasons. First, this syntax appears ambiguious (it is not possible to syntactically distiguish limited_unit_specifier from other identifiers). Second, the wording to describe the checks and meaning of this is complicated. Third, given that Ada includes child units, the nested unit containing a completing type can almost always be placed into a child unit, whereupon type_stubs as defined here can be used. Similarly, existing Ada facilities often can be used in that case, eliminating the need for stubs. Lastly, packages large enough to need this facility are quite rare.
We considered having some restriction relating to specifying private child packages. However, it was unclear what the rule should be, and there seemed no particular benefit in adding the complexity. Clearly if the completion is in a private child, only packages that have visibility on that child can make use of the completion, and can dereference an access-to-type-stub. But there seems no particular harm in allowing the type stub to specify a private child. Without actually "looking" at the specified package, it may not be easy to determine whether it is a private child. If the check is made when the stub is completed, then a somewhat artificial check needs to be made that the location of the type stub is inside the subsystem where the completing package is visible. An important property is that changing a private child, or adding or removing a private child, have no effect outside its "subsystem." That remains true even without any additional check, since the type stub by itself is legal, it is the usages that would be affected, and they would all have to be inside the subsystem.
!example
Here is the classic case of mutual dependence, where an employee belongs to a particular department, and a department has a manager who is an employee. (We assume the use of tagged types here to illustrate the use of tagged incomplete types.)
The example uses separate packages as package abstracts, which is usually advisable to have single well defined place for the access types. If it is desired to have the access type also be available in the completing package, that can be accomplished with a subtype declaration, as illustrated in package Employees.
limited with Employees; package Employees_Abstract is type Employee is tagged separate of Employees.Employee; type Emp_Ptr is access all Employee'Class; end Employees_Abstract;
limited with Departments; package Departments_Abstract is type Department is tagged separate of Departments.Department; type Dept_Ptr is access all Department'Class; end Departments_Abstract;
with Departments_Abstract, Employees_Abstract; package Employees is type Employee is tagged private; subtype Emp_Ptr is Employees_Abstract.Emp_Ptr; procedure Assign_Employee(E : in out Employee; D : in out Departments_Abstract.Department'Class); ... function Current_Department(D : in Employee) return Departments_Abstract.Dept_Ptr; end Employees;
with Departments_Abstract, Employees_Abstract; package Departments is type Department is tagged private; procedure Choose_Manager(D : in out Department; Manager : in out Employees_Abstract.Employee'Class); ... end Departments;
--Note: Corrigendum sections not updated. --!corrigendum 3.10.1(2) -- --@drepl --@xindent<@fa<incomplete_type_declaration ::= @b<type> defining_identifier [discriminant_part];>> --@dby --@xindent<@fa<incomplete_type_declaration ::= @b<type> defining_identifier [discriminant_part] [@b<is tagged>];@hr -- | type_stub>> -- --@xindent<@fa<type_stub ::= @b<type> defining_identifier [discriminant_part] @b<is> [@b<tagged>]@hr -- @b<separate in> abstracted_package_specifier;>> -- --@xindent<@fa<abstracted_package_specifier ::= identifier |@hr -- abstracted_package_specifier . identifier>> -- --!corrigendum 3.10.1(3) -- --@drepl --An @fa<incomplete_type_declaration> requires a completion, which shall be a --@fa<full_type_declaration>. If the @fa<incomplete_type_declaration> occurs --immediately within either the visible part of a @fa<package_specification> --or a @fa<declarative_part>, then the @fa<full_type_declaration> shall occur --later and immediately within this visible part or @fa<declarative_part>. If --the @fa<incomplete_type_declaration> occurs immediately within the private part --of a given @fa<package_specification>, then the @fa<full_type_declaration> --shall occur later and immediately within either the private part itself, or --the @fa<declarative_part> of the corresponding @fa<package_body>. --@dby --An @fa<incomplete_type_declaration> other than a @fa<type_stub> requires a --completion, which shall be a @fa<full_type_declaration>. If the --@fa<incomplete_type_declaration> occurs immediately within either the visible --part of a @fa<package_specification> or a @fa<declarative_part>, then the --@fa<full_type_declaration> shall occur later and immediately within this --visible part or @fa<declarative_part>. If the @fa<incomplete_type_declaration> --occurs immediately within the private part of a given --@fa<package_specification>, then the @fa<full_type_declaration> shall occur --later and immediately within either the private part itself, or the --@fa<declarative_part> of the corresponding @fa<package_body>. -- --A @fa<type_stub> includes a @fa<abstracted_package_specifier> which specifies --the full expanded name of the package in which its completion is expected to --occur. Certain uses (see below) of a name that denotes the @fa<type_stub> or --a value of an access type that designates the @fa<type_stub>, require that --the completion exist. In these cases, the completion shall occur in the --visible part of the specified package, and be a @fa<type_declaration> other --than an @fa<incomplete_type_declaration>; the @fa<abstracted_package_specifier> --shall be the full expanded name of this package (starting with a root --library unit, and using no renaming declarations), and the package shall be --a library package. -- --!corrigendum 3.10.1(4) -- --@drepl --If an @fa<incomplete_type_declaration> has a @fa<known_discriminant_part>, then --a @fa<full_type_declaration> that completes it shall have a fully conforming --(explicit) @fa<known_discriminant_part> (see 6.3.1). If an --@fa<incomplete_type_declaration> has no @fa<discriminant_part> (or an --@fa<unknown_discriminant_part>), then a corresponding @fa<full_type_declaration> --is nevertheless allowed to have discriminants, either explicitly, or inherited --via derivation. --@dby --If an @fa<incomplete_type_declaration> includes the keyword @b<tagged>, then a --@fa<type_declaration> that completes it shall declare a tagged type. --If an @fa<incomplete_type_declaration> has a @fa<known_discriminant_part>, then --a @fa<type_declaration> that completes it shall have a fully conforming --(explicit) @fa<known_discriminant_part> (see 6.3.1). If an --@fa<incomplete_type_declaration> has no @fa<discriminant_part> (or an --@fa<unknown_discriminant_part>), then a corresponding @fa<type_declaration> --is nevertheless allowed to have discriminants, either explicitly, or inherited --via derivation. In the case of a @fa<type_stub>, these checks are performed no --later than when a construct requires the completion to be available. -- -- --!corrigendum 3.10.1(5) -- --@drepl --The only allowed uses of a name that denotes an @fa<incomplete_type_declaration> --are as follows: --@dby --A name that denotes an @fa<incomplete_type_declaration> may be used as follows: -- --!corrigendum 3.10.1(8) -- --@drepl --@xbullet<as the @fa<subtype_mark> in an @fa<access_definition>;> --@dby --@xbullet<as the @fa<subtype_mark> in an @fa<access_definition>.> -- --A name that denotes an incomplete_type_declaration that includes the --keyword @b<tagged> may also be used as follows: -- --@xbullet<as the @fa<subtype_mark> defining the subtype of a parameter in a --@fa<formal_part>;> -- -- --!corrigendum 3.10.1(9) -- --@drepl --@xbullet<as the @fa<prefix> of an @fa<attribute_reference> whose --@fa<attribute_designator> is Class; such an @fa<attribute_reference> is --similarly restricted to the uses allowed here; when used in this way, the --corresponding @fa<full_type_declaration> shall declare a tagged type, and the --@fa<attribute_reference> shall occur in the same library unit as the --@fa<incomplete_type_declaration>.> --@dby --@xbullet<as the @fa<prefix> of an @fa<attribute_reference> whose --@fa<attribute_designator> is Class; such an @fa<attribute_reference> is --restricted to the uses allowed above.> -- --If a name that denotes an @fa<incomplete_type_declaration> is used in other --contexts, the @fa<incomplete_type_declaration> shall be a @fa<type_stub>, and --the completion shall be @i<available> at the place of use, as defined by --either of the following conditions: -- --@xbullet<the place of use is within the immediate scope of the completion of --the @fa<type_stub>; or> -- --@xbullet<the place of use is within the scope of a @fa<with_clause> that --mentions the package specified by the @fa<abstracted package> of the --@fa<type_stub>.> -- --The completion of an @fa<incomplete_type_declaration> that is not a --@fa<type_stub> is defined to be available throughout the (extended) scope --of the completion. The completion of an incomplete class-wide type is --available wherever the completion of the root of the class is available. -- --!corrigendum 3.10.1(10) -- --@drepl --A dereference (whether implicit or explicit -- see 4.1) shall not be of an --incomplete type. --@dby --A dereference (implicit or explicit -- see 4.1) of a value of an access type --whose designated type @i<D> is incomplete is allowed only in the following --contexts: -- --@xbullet<in a place where the completion of @i<D> is available (see above);> -- --@xbullet<in a context where the expected type is @i<E> and> --@xinbull<@i<E> covers the completion of @i<D>,> --@xinbull<@i<E> is tagged and covers @i<D>,> --@xinbull<@i<E> covers @i<D>'Class or its completion, or> --@xinbull<@i<E>'Class covers @i<D> or its completion;> -- --@xbullet<as the target of an @fa<assignment_statement> where the type of the --value being assigned is @i<V>, and @i<V> or @i<V>'Class is the completion of --@i<D>.> -- --In these contexts, the incomplete type is defined to be the same type as --completion, and its first subtype statically matches the first --subtype of its completion. -- --!corrigendum 3.10.1(11) -- --@drepl --An @fa<incomplete_type_declaration> declares an incomplete type and its first --subtype; the first subtype is unconstrained if a @fa<known_discriminant_part> --appears. --@dby --An @fa<incomplete_type_declaration> declares an incomplete type and its --first subtype; the incomplete type is tagged if the keyword @b<tagged> --appears; the first subtype is unconstrained if a @fa<known_discriminant_part> --appears. Two @fa<type_stub>s are defined to be the same type if they have the --same defining identifier, the same sequence of identifiers in their --@fa<abstracted_package_specifier>s, and their first subtypes match statically. -- --!corrigendum 10.01.2(3) -- --@drepl --@xindent<@fa<context_item ::= with_clause | use_clause>> --@dby --@xindent<@fa<context_item ::= with_clause | use_clause | abstract_clause>> -- --!corrigendum 10.01.2(4) -- --@dinsa --@xindent<@fa<with_clause ::= @b<with> @i<library_unit_>name {, @i<library_unit_>name }>> --@dinst --@xindent<@fa<abstract_clause ::= [@b<private>] @b<abstract of> abstracted_package_specifier;>> -- --!corrigendum 10.01.2(8) -- --@dinsa --If a @fa<with_clause> of a given @fa<compilation_unit> mentions a private child --of some library unit, then the given @fa<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. --@dinss --The @fa<abstracted_package_specifier> of an @fa<abstract_clause> that appears on --a @fa<library_unit_declaration> or @fa<library_unit_renaming_declaration> may be --used in entire declarative region of the declaration, which includes --all children and subunits. The @fa<abstracted_package_specifier> of an --@fa<abstract_clause> that appears on a body may be used in that body, --including all subunits. -- --A @fa<abstracted_package_specifier> defined only in @fa<abstract_clause>s that --include the reserved word @b<private> shall be used only within --@xbullet<a private part,> --@xbullet<a body,> --@xbullet<a private descendant of the unit on which one of these --@fa<abstract_clause>s appear.> -- --!corrigendum J.10(1) -- --@dinsc --For the first subtype S of a type T declared by an --@fa<incomplete_type_declaration> that is not tagged and is not a type stub, the --following attribute is defined: -- --@xhang<@xterm<S'Class>Denotes the first subtype of the incomplete class-wide --type rooted at T. The completion of T shall declare a tagged type. Such an --attribute reference shall occur in the same library unit as the --@fa<incomplete_type_declaration>.
!ACATS test
A series of B and C tests should be constructed for this proposal.
!appendix

[For discussion on the once-approved version of this proposal, see AI-00217-04.]

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

From: Pascal Leroy
Sent: Tuesday, December 17, 2002,  5:03 AM

I am forwarding the following message from John to the ARG mailing list because
I would like to get the ball rolling.

AI 217 was rejected by WG9 because of the objection/proposal below.  I want to
get a resolution on this issue at the Padua meeting, so that we can send this
AI (which I view as very important) to WG9 in June.

As John points out, moving the stub declaration at the front of the unit brings
us back to the "with type" proposal, and we know that this one is full of
problems.

The notion of having a new kind of with clause for the sole purpose of human
readability makes some sense, but then there is very little semantics there,
and I am not too excited by the idea of adding a completely new construct which
has about the same value as a comment (OK, not quite).

What do other people think?

Pascal
--
> AI-217 is type stubs of course.
>
> The issued raised at the presentation made by Tuck was that
> many people from the floor objected to a package P being
> mentioned in the stub
>
>    type T is ... separate in package P.
>
> inside the text of a unit Q and that there was no mention of
> P in the context clause for Q.
>
> I think the audience took on board the fact that the whole
> point was that Q must not depend on P and so a regular with
> clause was not possible. However they did not like the
> textual lurking and wanted some sort of up-front mention if
> only for the benefit of the human reader.
>
> What I thought was a sound suggestion from the floor was
> that maybe we could have a "with out" clause for P which
> gave the human reader visibility but no Ada dependence. This
> was greeted with a certain amount of mirth (perhaps because
> of the way in which I suggested it).
>
> One other suggestion from the floor was that maybe the whole
> stub declaration should be up front but that seemed
> unhealthy to me and would have a flavour of going back to
> the with type idea.
>
> Anyway, that was it.

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

From: Robert A Duff
Sent: Tuesday, December 17, 2002,  8:31 AM

> I am forwarding the following message from John to the ARG mailing
> list because I would like to get the ball rolling.
>
> AI 217 was rejected by WG9 because of the objection/proposal below.

This seems like, how does that saying go, "perfection is the enemy of
the good", or something like that?  Technically, the objection is right:
there *should* be some mention of that package in the context clause.
But from a practical point of view:  As an Ada user, I've been waiting
desperately for a solution to this serious language flaw for 7 years.
We've finally got a solution that works, and now folks want to hold it
up for perhaps another year or more to solve a relatively minor problem?
Grrr.

>...I
> want to get a resolution on this issue at the Padua meeting, so that
> we can send this AI (which I view as very important) to WG9 in June.

Wishful thinking.  The ARG has never been able to work that quickly.
At the Padua meeting, we will be in the "Norm Cohen mode", of cobbling
together vaguely readable syntax out of existing reserved words (because
adding new reserved words is viewed in the Ada community as morally akin
to consorting with the devil).  Then somebody will go off and write it
up, and we will need *another* meeting to actually vote on it.  And
there's a nonnegligible probability that we will get bogged down in an
argument about the tastefulness of the proposed syntax (see "mirth"
below), requiring a third meeting.  Historically, no serious technical
work gets done *between* meetings.

OK, enough ranting.  I can live with the proposal as is, or I can live
with an extra thing in the context clause, or I can live with putting
the whole thing in the context clause if that works.

> As John points out, moving the stub declaration at the front of the
> unit brings us back to the "with type" proposal, and we know that this
> one is full of problems.

Could someone explain that in more detail?  Why should merely shuffling
the syntax around cause trouble?  Can we shuffle the syntax without
changing the semantics?

> The notion of having a new kind of with clause for the sole purpose of
> human readability makes some sense, but then there is very little
> semantics there, and I am not too excited by the idea of adding a
> completely new construct which has about the same value as a comment
> (OK, not quite).

Ada has lots of features whose primary purpose is "comment", except with
one huge advantage: the reader has some confidence that you're not
lying, because the compiler checks the rules.  So I don't mind having a
new kind of with clause that is merely a (compiler-checked) comment.

> What do other people think?
>
> Pascal
> --
> > AI-217 is type stubs of course.
> >
> > The issued raised at the presentation made by Tuck was that
> > many people from the floor objected to a package P being
> > mentioned in the stub
> >
> >    type T is ... separate in package P.
> >
> > inside the text of a unit Q and that there was no mention of
> > P in the context clause for Q.
> >
> > I think the audience took on board the fact that the whole
> > point was that Q must not depend on P and so a regular with
> > clause was not possible. However they did not like the
> > textual lurking and wanted some sort of up-front mention if
> > only for the benefit of the human reader.
> >
> > What I thought was a sound suggestion from the floor was
> > that maybe we could have a "with out" clause for P which
> > gave the human reader visibility but no Ada dependence. This
> > was greeted with a certain amount of mirth (perhaps because
> > of the way in which I suggested it).

I can live with "with out".  But I can see why some folks find it
silly.  How about:

    with separate P;

or

    with separate type in P; -- Norman would like that.  ;-)

The Legality Rule would presumably be that if you say "type T is
separate in package P;", you must be within the scope of a "with
separate P;" clause.

> > One other suggestion from the floor was that maybe the whole
> > stub declaration should be up front but that seemed
> > unhealthy to me and would have a flavour of going back to
> > the with type idea.
> >
> > Anyway, that was it.

Tucker mentioned another issue: Some people use the style where every
type in the program has the same name: "Object" or "T" or "Instance",
and the actual semantics is encoded in the package name.  So if you want
types "Doctors_Package.Object" and "Patients_Package.Object" to be
mutually recursive, you can't do it.  Is that the issue, Tuck?

My response is, "So don't do that."

Besides, if you really want it to be called "Object", can't you always
rename "subtype Object is Doctor_Package.Doctor_Type;" to work around
the problem?  Is there a better solution?

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

From: Pascal Leroy
Sent: Tuesday, December 17, 2002,  9:16 AM

> This seems like, how does that saying go, "perfection is the enemy of
> the good", or something like that?  Technically, the objection is right:
> there *should* be some mention of that package in the context clause.
> But from a practical point of view:  As an Ada user, I've been waiting
> desperately for a solution to this serious language flaw for 7 years.
> We've finally got a solution that works, and now folks want to hold it
> up for perhaps another year or more to solve a relatively minor problem?
> Grrr.

I couldn't agree more.

> Wishful thinking.

You're probably right :-(

> > As John points out, moving the stub declaration at the front of the
> > unit brings us back to the "with type" proposal, and we know that this
> > one is full of problems.
>
> Could someone explain that in more detail?  Why should merely shuffling
> the syntax around cause trouble?  Can we shuffle the syntax without
> changing the semantics?

I suppose you could, but that doesn't make sense to me.  You would have a
declaration occurring in a context clause.  That's a whole new mechanism, and
certainly not an intuitive one.  I believe we want to preserve the invariant
that the context clause describes what is imported by a unit, and the visible
part contains the declaration exported by the unit.

> Ada has lots of features whose primary purpose is "comment", except with
> one huge advantage: the reader has some confidence that you're not
> lying, because the compiler checks the rules.  So I don't mind having a
> new kind of with clause that is merely a (compiler-checked) comment.

That's true in general, but here I fail to see that it buys you any safety at
all.  The only reason why you would have to type this new with clause is so that
the compiler can check the type stubs against it.  But then the compiler and/or
linker are surely going to check the package identifier occurring in the type
stub at some point.  So what's the big deal?

Consider the following analogy: body stubs can be scattered in a unit and they
do not need to be declared at the beginning of that unit.  Would it be useful
to require such declarations?  I don't think so.  OK, occasionally I forget to
provide a subunit, and I only discover the problem at link time.  But it
doesn't happen often in real life, and it doesn't compromise the safety of my
programs.

> How about:
>
>     with separate P;
>
> or
>
>     with separate type in P; -- Norman would like that.  ;-)

That sounds better than "with out".

> Tucker mentioned another issue: Some people use the style where every
> type in the program has the same name: "Object" or "T" or "Instance",
> and the actual semantics is encoded in the package name.  So if you want
> types "Doctors_Package.Object" and "Patients_Package.Object" to be
> mutually recursive, you can't do it.  Is that the issue, Tuck?
>
> My response is, "So don't do that."
>
> Besides, if you really want it to be called "Object", can't you always
> rename "subtype Object is Doctor_Package.Doctor_Type;" to work around
> the problem?  Is there a better solution?

This particular topic was discussed at the Cupertino meeting, and the
conclusion was that this was not important enough to make the construct more
complex.  I don't think we should revisit decisions that have been made after
extensive discussion, unless there is a new technical element that could modify
the conclusion.  Otherwise we are just never going to make any progress.

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

From: Barbey, St‚phane
Sent: Tuesday, December 17, 2002  9:22 AM

Robert A. Duff wrote:
> Tucker mentioned another issue: Some people use the style where every
> type in the program has the same name: "Object" or "T" or "Instance",
> and the actual semantics is encoded in the package name.  So if you want
> types "Doctors_Package.Object" and "Patients_Package.Object" to be
> mutually recursive, you can't do it.  Is that the issue, Tuck?
>
> My response is, "So don't do that."

... except it is heavily used by the IDL2Ada compilers (and BTW IDL has
a concept of forward declarations that would be much easier to work with
in Ada with if the ARG gets this AI right...)

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

From: Pascal Leroy
Sent: Tuesday, December 17, 2002, 10:06 AM

The AI explains (in the !example section) that it is advisable to introduce an
_Interface package to declare the type stubs.  The reason is that if you have
types that are involved in more than one cycle, this provides the best
structure.

With this approach, the example from the AI works fine even if everything is
named Object:

    package Employees_Interface is
        type Object is tagged separate in Employees;
        type Emp_Ptr is access all Object'Class;
    end Employees_Interface;

    package Departments_Interface is
        type Object is tagged separate in Departments;
        type Dept_Ptr is access all Object'Class;
    end Departments_Interface;

    with Departments_Interface, Employees_Interface;
    package Employees is
        type Object is tagged private;
        procedure Assign_Employee(E : in out Object;
                                  D : in out Departments_Interface.Object);
        ...
        function Current_Department(D : in Object) return
            Departments_Interface.Dept_Ptr;
    end Employees;

    with Departments_Interface, Employees_Interface;
    package Departments is
        type Object is tagged private;
        procedure Choose_Manager(D : in out Object;
                                 Manager : in out Employees_Interface.Object);
        ...
    end Departments;

With this approach the _Interface package effectively works as a forward
declaration.  The issue raised by Bob only exists if there is no _Interface
package and Employees and Departments directly declare type stubs for each
other.

I don't know what IDL compilers do, but it would be much easier to
systematically generate an _Interface package, than to detect the case where
direct dependence is possible.

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

From: Ben Brosgol
Sent: Tuesday, December 17, 2002 10:41 AM

> > This seems like, how does that saying go, "perfection is the enemy of
> > the good", or something like that?  Technically, the objection is right:
> > there *should* be some mention of that package in the context clause.
> > But from a practical point of view:  As an Ada user, I've been waiting
> > desperately for a solution to this serious language flaw for 7 years.
> > We've finally got a solution that works, and now folks want to hold it
> > up for perhaps another year or more to solve a relatively minor problem?
> > Grrr.
>
> I couldn't agree more.

Since neither Bob nor Pascal were present at Tuck's briefing to the SIGAda
attendees, let me set some context.  Tuck did not pose the question "Would
you rather have the proposed solution now, or a 'perfect' solution in a
year?"  If he had, then maybe the audience's response would have been
different.  Rather, his intent was just to get a sense of whether what the
ARG has been doing will meet the needs / expectations of typical users.  The
response, at least on the interdependent types AI, seemed pretty clear to me
(and also apparently to WG9, although I was not present at the WG9 meeting).
The people who cared expressed their opinions very cogently.  Solving 99.9%
of a problem is fine, but if the last .1% is perceived as important by
customers, then either convince the customer that they're wrong, or else
solve the problem.

As for the "it will take a year to solve", my reaction is: so what.  I don't
see compiler vendors rushing to get this stuff implemented.  In any event,
unless there are some other problems with the AI (in which case there would
be a delay anyway), the only issue is the choice of syntax for the context
clause item.  So even before the eventual final approval of the AI, people
(users and implementors) have a pretty good idea of what the feature will
look like.

By the way, where is the current version of this AI?  I looked at the web
site http://www.ada-auth.org/cgi-bin/cvsweb.cgi/AIs/AI-00217.TXT but the
latest version shown there is pretty old.

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

From: Randy Brukardt
Sent: Tuesday, December 17, 2002 12:45 AM

The AI we approved is "alternative 4" (or AI95-00217-04), so it is found in
the file AI-30217.TXT. So the correct URL is:
http://www.ada-auth.org/cgi-bin/cvsweb.cgi/AIs/AI-30217.TXT

We need to declare the others !No Action at some point, both to get them off
of the agenda and to help avoid mistakes...

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

From: Tucker Taft
Sent: Tuesday, December 17, 2002 10:59 AM

I will certainly take some of the blame for this,
because I didn't have ready arguments to justify
not having some visibility on the type stub in a context clause.

However, it was a surprise to me that this was the one
proposal that received widespread negative response, whereas
interfaces, object.operation, etc., all received almost unanimous
positive support.

The ..._Interface package "idiom" does seem like a reasonable
solution to the "type Object is" approach.  The question is whether
the idiom can also be considered to resolve the other objection,
because the _Interface packages are so short.

People do like Ada's context clause, and I do find Java's inconsistent
use of imports a bit weird.  In Java, if you give the full name of a class
(i.e. including its full package name prefix) where it is used,
then you don't need an "import" clause for the class.  Essentially
a Java "import" clause for a class makes the class name directly
visible (with no package prefix required), so it is closer to
a "use" clause for the enclosing package, than a "with" clause
for the class.  By contrast, the fact that Ada's context clauses
indicate all external references seems like a very good thing.

There seem to be various options to solve this problem:

1) Encourage use of the "..._Interface" idiom.
2) Add some kind of new "with" clause for packages that does
   not create a semantic dependence on the package.
   Only such packages may be mentioned in type stubs.
3) Add a new kind of "with" clause for types, that does
   not create a dependence on the package containing the type,
   and allows a renaming as part of the "with", effectively
   introducing the simple type name as an incomplete type
   implicitly declared immediately within the compilation unit
   having the "with" clause.
4) Add a new kind of "with" clause for types that implicitly
   creates an "incomplete" package for every package mentioned
   in the "with type" clause.  Such incomplete packages must
   not turn out to be renames (renames were a big bugaboo of
   the earlier attempts at "with type").

Number 4 is pretty much back to the old "with type", except
perhaps we have learned that renaming is bad news.

Number 1 is keeping what we have now.

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

From: Randy Brukardt
Sent: Tuesday, December 17, 2002 1:02 PM

Ben said:

> As for the "it will take a year to solve", my reaction is: so what. I don't
> see compiler vendors rushing to get this stuff implemented.

Well, I think that's wrong. Tucker already implemented a version of it in
their compiler. I've been planning to do so as soon as I get some time,
because it is badly needed to fix some structure problems in the Claw GUI
Builder. I thought Pascal had indicated that they would be doing it soon. So
there does seem to be some "rush to implement it"

This is probably the most important AI of anything proposed for the
amendment; certainly in the top two or three. We needed a solution for it
years ago (roughly 25 years ago, I think), and holding it up over some
perceived lack is dubious at best.

> In any event, unless there are some other problems with the AI (in which
> case there would be a delay anyway), the only issue is the choice of
> syntax for the context clause item.

No, there is at least one other solution, which is to revert to alternative
#3, which does not specify the completing unit in the type stub. I don't
know if that would satisify people or make them more uncomfortable - but it
certainly gets rid of the "hidden" "dependence" (which is neither).

I do agree that moving the declaration doesn't work, simply because it is a
declaration. Thus, its location controls its visibility. To try to move it
to the context clause would be a disaster (new mechanism, we'd need new
rules to allow private declarations and rep. clauses and on and on and on.)

In any case, we can at least take one meeting out of the cycle by coming to
some sort of consensus here, and writing that proposal up beforehand (as
alternative #5, I suppose).

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

From: Randy Brukardt
Sent: Tuesday, December 17, 2002 1:19 PM

> There seem to be various options to solve this problem:
>
> 1) Encourage use of the "..._Interface" idiom.
> 2) Add some kind of new "with" clause for packages that does
>    not create a semantic dependence on the package.
>    Only such packages may be mentioned in type stubs.

You forgot:

2A) (should be three, but I'm not going to renumber the others): Move the
dependence to the completor (as in alternative #3). (I always objected to
the "magic" semantics of the name in the stub.) The problems with that
proposal (which seemed minor) would have to be revisited. (As I recall, the
primary reason that this alternative was abandoned was that some ARG members
didn't like the lack of indication about where the expected completion was.

> 3) Add a new kind of "with" clause for types, that does
>    not create a dependence on the package containing the type,
>    and allows a renaming as part of the "with", effectively
>    introducing the simple type name as an incomplete type
>    implicitly declared immediately within the compilation unit
>    having the "with" clause.
> 4) Add a new kind of "with" clause for types that implicitly
>    creates an "incomplete" package for every package mentioned
>    in the "with type" clause.  Such incomplete packages must
>    not turn out to be renames (renames were a big bugaboo of
>    the earlier attempts at "with type").

#3 and #4 are way over the top; I see no reason to think about them further.

That leaves us with the other three. The main question is whether #2A helps
the problem, or makes people uncomfortable in the different way. And the
answer to that question really drives the choice: if people really want a
dependency to be declared (at the top) of the unit containing the stub, then
no solution other than #2 can be used. (That seems to be Ben's position.) If
the answer is that people are concerned about hidden dependencies, but are
not bothered by the lack of a dependency, then #2A should be pursued. And if
answer is that the majority of people want this now and don't care that much
about it, then we should stick to #1.

As far as the naming question goes, Pascal is right, we did discuss that in
Cupertino. And we got the wrong answer IMHO. I don't see that allowing (or
better still, requiring) type names in the stub makes the proposal any more
complicated at all. And I know that conflicting type names are quite common,
and I don't much like the answer of "don't do that!". But since I voted for
that feature (and was outvoted), I don't get to reopen it. :-)

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

From: Robert A. Duff
Sent: Tuesday, December 17, 2002 1:19 PM

> Tucker already implemented a version of it in
> their compiler.

It was Sheri Bernstein, actually.  I believe that implementation is
"incomplete".  I think having the final proposal nailed down would make
vendors less reluctant to implement it.  And if we all implement the
same thing, that would be a Good Thing for the Ada community.  ;-)

>... I've been planning to do so as soon as I get some time,
> because it is badly needed to fix some structure problems in the Claw GUI
> Builder. I thought Pascal had indicated that they would be doing it soon. So
> there does seem to be some "rush to implement it"
>
> This is probably the most important AI of anything proposed for the
> amendment; certainly in the top two or three.

Yeah, I'd say it's second only to the "abstract interfaces" thing.

> In any case, we can at least take one meeting out of the cycle by coming to
> some sort of consensus here, and writing that proposal up beforehand (as
> alternative #5, I suppose).

Sounds good to me.  Perhaps our esteemed chair will pester us enough so
that when the vote comes in Padua, we'll all know ahead of time how it's
going to turn out.  ;-)

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

From: Michael F. Yoder
Sent: Tuesday, December 17, 2002 1:59 PM

Disclaimer: I've never had a need for the feature under discussion, and
so I'm speaking from a "what if" perspective here; and from the user's
point of view, not the implementer's.

My first reaction is, the objection as presented actually doesn't seem
so unreasonable. But then I've not been expending bodily fluids on
behalf of the proposal.  :-)

My second is, that option 2 is preferable to the others. As a wickerman
proposal, how about

      with type in P1, ..., Pn;

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

From: Dan Eilers
Sent: Tuesday, December 17, 2002 2:33 PM

Tuck wrote:
> There seem to be various options to solve this problem:
> ...
> 2) Add some kind of new "with" clause for packages that does
>    not create a semantic dependence on the package.
>    Only such packages may be mentioned in type stubs.
> ...

There seems to be a potential orthogonality with AI 262 (private with),
if a user wants to indicate that the with'd unit can only be mentioned
in type stubs, and only in the private part.

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

From: John Barnes
Sent: Tuesday, December 17, 2002 10:39 AM

>>...I >> want to get a resolution on this issue at the Padua meeting, so that
>> we can send this AI (which I view as very important) to WG9 in June.

My view is that we don't *have* to do anything. It would be
quite reasonable for us to say that we have given it deep
reconsideration and have concluded that it is best the way
it is. Which is probably true.

The United Kingdom would be happy with that conclusion I am
sure.

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

From: Jean-Pierre Rosen
Sent: Wednesday, December 18, 2002 1:42 AM

> My second is, that option 2 is preferable to the others. As a wickerman
> proposal, how about
>
>       with type in P1, ..., Pn;

Actually, I proposed the same idea to Tuck in Houston, but with the syntax:
with package abstract Pack is
   type T1;
   type T2;
end package;

(only incomplete type declarations allowed, nothing else).

You can view this either as:
- A revival of the the abstract package, without creating new kind of compilation units
- JAS (Just Another Syntax) for the type stub (same effect as "type T1 is separate in Pack", just appearing in another place)
- Forcing a (partial) source compilation model on every compiler :-)

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

From: Pascal Leroy
Sent: Wednesday, December 18, 2002 3:49 AM

> As for the "it will take a year to solve", my reaction is: so what.  I don't
> see compiler vendors rushing to get this stuff implemented. In any event,
> unless there are some other problems with the AI (in which case there would
> be a delay anyway), the only issue is the choice of syntax for the context
> clause item.  So even before the eventual final approval of the AI, people
> (users and implementors) have a pretty good idea of what the feature will
> look like.

I completely disagree with this analysis.

First, any time spent by the ARG on 217 is time that is not spent on other
AIs.  So the question is as usual one of opportunity cost: what AIs are
currently on the table that we want to bury for the sole purpose of
marginally improving 217?

Second, you have to remember that we are not doing this intellectual
exercise in a vacuum: we have a schedule imposed by WG9, and this schedule
calls for finalizing proposals a year from now.  The worst that could happen
is that revisiting 217 would either cause the entire revision to slip, or
cause 217 to not be included in the amendment.

Third, your comment about vendors is misguided, and may represent the
position of your employer, but not that of other vendors.  Speaking for
Rational, we had a plan to start implementing some of the amendment AIs in
the next few months, for inclusion in a release that will reach customers
around the end of 2003, and 217 was part of that effort.  The fact that this
AI is now back on the drawing board means that we will probably cancel this
effort (unless the Padua meeting clarifies the situation) so support for 217
in our products will slip to mid-2005.  Who knows what IBM will decide is
the right thing to do in that time frame?

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

From: Pascal Leroy
Sent: Wednesday, December 18, 2002 3:56 AM

> There seem to be various options to solve this problem:
>
> 1) Encourage use of the "..._Interface" idiom.
> 2) Add some kind of new "with" clause for packages that does
>    not create a semantic dependence on the package.
>    Only such packages may be mentioned in type stubs.
> 3) Add a new kind of "with" clause for types, that does
>    not create a dependence on the package containing the type,
>    and allows a renaming as part of the "with", effectively
>    introducing the simple type name as an incomplete type
>    implicitly declared immediately within the compilation unit
>    having the "with" clause.
> 4) Add a new kind of "with" clause for types that implicitly
>    creates an "incomplete" package for every package mentioned
>    in the "with type" clause.  Such incomplete packages must
>    not turn out to be renames (renames were a big bugaboo of
>    the earlier attempts at "with type").

I think stylistically #1 is a good idea regardless of what language features
we add.

I could go with #2 if we can quickly agree on a syntax/semantics and discuss
that at Padua.

If we want to allow renaming (which I believe is unnecessary because of #1)
this must be done in the type stub declaration, not in the with clause as #3
seems to imply.  The with clause must only be used to reference the package,
not the type.  But I'd rather not reopen the renaming issue since it was
extensively discussed at Cupertino.

#4 is effectively the old "with type", but if you reread the minutes of the
meetings where this proposal was discussed, you'll see that renaming was
only one of the many problems with this idea.  One of the things that we
wanted to do with "with type" was to allow importing of access types (to
avoid having many different access types and conversions all over the
place).  But then the representation items associated with access types were
problematic.  And there were issues associated with the non-transitivity of
with clauses, which caused ripple effects in semantic dependencies.

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

From: Pascal Leroy
Sent: Wednesday, December 18, 2002 4:07 AM

> You forgot:
>
> 2A) (should be three, but I'm not going to renumber the others): Move the
> dependence to the completor (as in alternative #3). (I always objected to
> the "magic" semantics of the name in the stub.) The problems with that
> proposal (which seemed minor) would have to be revisited. (As I recall, the
> primary reason that this alternative was abandoned was that some ARG members
> didn't like the lack of indication about where the expected completion was.

If you look at the history of 217/03 (funny how we seem to forget all these
issues that we discussed to death), you'll see that there were two main
problems:

1 - How do you specify that a full type completes a stub?  (We considered
syntax that would make the full type declarations even more complicated, or
representation-item-like syntax, but none of that was satisfactory).

2 - You need to deal with the situation where a stub has several
completions.  This requires a lot of additional post-compilation checking,
and errors may end up being detected very late in the development process.

I find it curious that the users are telling us "we want to be more
explicit/safe in specifying which unit contains the completion" and #2A
answers that objection by saying "we won't let you specify where the
completion lives" ;-)

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

From: Pascal Leroy
Sent: Wednesday, December 18, 2002 4:12 AM

> My first reaction is, the objection as presented actually doesn't seem
> so unreasonable. But then I've not been expending bodily fluids on
> behalf of the proposal.  :-)

The objection is not unreasonable, but the question is: is it important
enough to reopen the AI?  If all we do is quickly agree on the
syntax/semantics of a new kind of with clause, fine.  But the recent mail
traffic has shown that we were reopening all sorts of all discussions, and
that's the best way to lose a year.

> My second is, that option 2 is preferable to the others. As a wickerman
> proposal, how about
>
>       with type in P1, ..., Pn;

I am rather sick and tired with the combination of words "with type" but
other than that I am not going to argue about the syntax.  We'll have a
straw vote anyway.

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

From: Pascal Leroy
Sent: Wednesday, December 18, 2002 4:13 AM

> There seems to be a potential orthogonality with AI 262
> (private with),
> if a user wants to indicate that the with'd unit can only be mentioned
> in type stubs, and only in the private part.

Good point, and an illustration that Nothing Is Simple.

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

From: Ben Brosgol
Sent: Wednesday, December 18, 2002 10:00 AM

> Second, you have to remember that we are not doing this intellectual
> exercise in a vacuum: we have a schedule imposed by WG9, and this schedule
> calls for finalizing proposals a year from now.  The worst that could happen
> is that revisiting 217 would either cause the entire revision to slip, or
> cause 217 to not be included in the amendment.

Part of the non-vacuum is the user community (i.e., the real customers of
the Amendment work), and indeed one of the purposes of Tucker's presentation
was to elicit a response to the AIs.  What was the sense of doing the
briefing if we are going to complain that we didn't like the response? :-)

The feeling that I got from the discussion of 217 (John, Tucker, Jean-Pierre
and maybe some others on this list were there so they can correct me if they
disagree) was that a number of individuals strongly felt that a lack of
something on the context clause was a violation of Ada design principles.
It also seemed that this could be addressed with a simple syntactic
addition.  (OK, getting agreement on the right syntax is maybe not so simple
:-)  I did not get the feeling from the discussion that this required
re-opening the AI for general surgery but maybe I'm being naive.  Some of
the suggestions that have appeared on this thread, e.g. "with type in P1,
P2, ...;" combined with alternative 2 seem to solve the problem.

It does not address the issue of the same type stub name appearing in more
than one "with type"d package.  But there are workarounds that may be
satisfactory.

The interdependent types issue seems to be one of the more important items
for the Amendment work, so I would be a bit surprised if this AI simply gets
dropped based on its rejection in its current form.

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

From: Dan Eilers
Sent: Wednesday, December 18, 2002 12:56 PM

I'd like to propose a solution to AI 217 based on the _Interface package
idea.

Pascal wrote:

> The AI explains (in the !example section) that it is advisable to introduce an
> _Interface package to declare the type stubs.  The reason is that if you have
> types that are involved in more than one cycle, this provides the best
> structure.
>
> With this approach, the example from the AI works fine even if everything is
> named Object:
>
>    package Employees_Interface is
>        type Object is tagged separate in Employees;
>        type Emp_Ptr is access all Object'Class;
>    end Employees_Interface;
>
>    package Departments_Interface is
>        type Object is tagged separate in Departments;
>        type Dept_Ptr is access all Object'Class;
>    end Departments_Interface;
>
>    with Departments_Interface, Employees_Interface;
>    package Employees is
>        type Object is tagged private;
>        procedure Assign_Employee(E : in out Object;
>                                  D : in out Departments_Interface.Object);
>        ...
>        function Current_Department(D : in Object) return
>            Departments_Interface.Dept_Ptr;
>    end Employees;
>
>    with Departments_Interface, Employees_Interface;
>    package Departments is
>        type Object is tagged private;
>        procedure Choose_Manager(D : in out Object;
>                                 Manager : in out Employees_Interface.Object);
>        ...
>    end Departments;

Instead of "Employees_Interface", what you'd really like to write is
"Employees.Interface", making explicit the connection to package Employees.
But this doesn't work because of the rule that disallows declaring a
child unit before its parent has been compiled (and you can't compile the
parent first due the circular dependencies).  So I propose to relax this
rule, with some new syntax to be explicit what's going on.

The proposed syntax is that a child unit can be declared using a tick
mark in place of the period, to indicate that its parent need not
previously have been compiled.  References would still use a period.

Rewriting the above example:

    package Employees'Interface is         -- new syntax
        type Object is tagged separate in Employees;
        type Emp_Ptr is access all Object'Class;
    end Employees'Interface;

    package Departments'Interface is
        type Object is tagged separate in Departments;
        type Dept_Ptr is access all Object'Class;
    end Departments'Interface;

    with Departments.Interface, Employees.Interface;
    package Employees is
        type Object is tagged private;
        procedure Assign_Employee(E : in out Object;
                                  D : in out Departments.Interface.Object);
        ...
        function Current_Department(D : in Object) return
            Departments.Interface.Dept_Ptr;
    end Employees;

    with Departments.Interface, Employees.Interface;
    package Departments is
        type Object is tagged private;
        procedure Choose_Manager(D : in out Object;
                                 Manager : in out Employees.Interface.Object);
        ...
    end Departments;

This not only makes the _Interface package cleaner, but it eliminates
the need for any special kind of "with" clause, and eliminates the
objectionable reference in type stubs to packages that haven't been
mentioned in a context clause.

Note that Interface as used here isn't special, its just a user-defined
child unit name.

Being able to declare a child unit before its parent has been compiled
may have uses as well (I think someone has asked for this before).

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

From: Robert A. Duff
Sent: Wednesday, December 18, 2002 1:20 PM

> Part of the non-vacuum is the user community (i.e., the real customers of
> the Amendment work), and indeed one of the purposes of Tucker's presentation
> was to elicit a response to the AIs.  What was the sense of doing the
> briefing if we are going to complain that we didn't like the response? :-)

Good point.  The ARG *should* be listening to the user community,
as best it can.  (We don't have a large budget for market studies...)

> The feeling that I got from the discussion of 217 (John, Tucker, Jean-Pierre
> and maybe some others on this list were there so they can correct me if they
> disagree) was that a number of individuals strongly felt that a lack of
> something on the context clause was a violation of Ada design principles.

And they are correct (although I can't get too excited about this
issue).

> It also seemed that this could be addressed with a simple syntactic
> addition.

It could be, but as you can see from the discussion so far, all kinds of
new (and not-so-new) proposals come out of the woodwork.  These new
ideas, and perhaps even rehashed old ideas, may have merit, but I think
it's a mistake to waste time studying them when we have a proposal that
basically works (after 7 years work so far!).

I suggest we stick to solving the exact problem, and no more, by adding
a new kind of with clause with no more semantics than "herein lie type
stubs pointing at package X".  If it works, we should agree on the
syntax via e-mail before the next meeting.  If not, we should stick to
the current proposal.  Either way, the vote at the next meeting should
be a formality.  Wishful thinking?

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

From: John Barnes
Sent: Wednesday, December 18, 2002 1:51 PM

Absolutely right. Nonody at that presentation wanted
anything fancy. just a mark to say "herein lie stubs in
package X".  I thought my suggestions of

with out X;

was just the job. But there the world is a dull place. So
maybe echoing Bobs phrase we could something more elaborate
such as

with in is separate at package X;

At Christmas on we can be generaous with reserved words.
Happy Holidays

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

From: David Emery
Sent: Wednesday, December 18, 2002 2:14 PM

>...
>with in is separate at package X;

Reminds me of the (pornographic) story Norm Cohen once wrote
using -only- reserved words.

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

From: Michael Yoder
Sent: Wednesday, December 18, 2002 2:02 PM

Robert A Duff wrote:

>I suggest we stick to solving the exact problem, and no more, by adding
>a new kind of with clause with no more semantics than "herein lie type
>stubs pointing at package X".  If it works, we should agree on the
>syntax via e-mail before the next meeting.  If not, we should stick to
>the current proposal.  Either way, the vote at the next meeting should
>be a formality.  Wishful thinking?

I agree. Going even further, can we choose a single person (I'll suggest
Tucker) to just pick a syntax they like? I'm willing to rubber-stamp in
advance whatever you guys come up with, insofar as that helps expedite
email discussions.

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

From: Robert A. Duff
Sent: Wednesday, December 18, 2002 2:02 PM

Sounds like a good plan to me.  I'd even be willing to draw straws to
see who gets to pick the syntax.

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

From: Robert Dewar
Sent: Wednesday, December 18, 2002 6:09 PM

> Sounds like a good plan to me.  I'd even be willing to draw straws to
> see who gets to pick the syntax.

Not me. I think the exact choice of syntax can be a significant issue. I
would like to recall the furious acrimony surrounding the basically not
very important distinction between

  type x is tagged record ...

and

  class x is record ...

:-)

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

From: Randy Brukardt
Sent: Wednesday, December 18, 2002 6:46 PM

And as further proof, see Erhard's reaction to the syntax proposed.

Still, determining the complexity of the semantics is probably the most
important for ARG purposes. The syntax can pretty much be changed at any
time.

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

From: Ed Schonberg
Sent: Wednesday, December 18, 2002 2:14 PM

>  I thought my suggestions of
>
>  with out X;
>
>  was just the job.

The pun is  confusing at first reading. Why not:

   with in X;


Can't be any shorter!

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

From: Randy Brukardt
Sent: Wednesday, December 18, 2002 2:12 PM

> I suggest we stick to solving the exact problem, and no more, by adding
> a new kind of with clause with no more semantics than "herein lie type
> stubs pointing at package X".  If it works, we should agree on the
> syntax via e-mail before the next meeting.  If not, we should stick to
> the current proposal.  Either way, the vote at the next meeting should
> be a formality.  Wishful thinking?

I agree completely. Indeed, I was going to do just that if no one else beat
me to it: create an alternative 5 that's the same as alternative 4 with the
addition of this syntax (including the wording), and then we can choose
between them.

Of course, if someone else does it before I do, I won't mind -- I've got
plenty of other ARG work to do with my limited time and budget.

Syntax-wise, I think I like Bob Duff's original suggestion (way back at 8am
yesterday) of
    with separate P;
which, as Dan points out, will need a private option:
    [private] with separate P;

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

From: Dan Eilers
Sent: Wednesday, December 18, 2002 2:50 PM

> which, as Dan points out, will need a private option:
>     [private] with separate P;
>
>             Randy.

Please don't credit/blame me for the "[private]" in this proposal.
My purpose in pointing it out was exactly the opposite, by
showing that adding a new kind of with clause to the AI 217 proposal
is not as simple as was originally thought.  And it is totally
unnecessary as well, since type stubs are most logically placed
in a child unit, and child units don't need with clauses for
their parents.  The only change needed to AI 217 is changing
the underscore in "Employees_Interface" to a dot or tick mark.

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

From: Robert A. Duff
Sent: Wednesday, December 18, 2002 3:30 PM

But you can't "with" a child unit without also "with"-ing its parent.
Clients need to depend upon the type stubs without depending on the
"real" type.

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

From: Dan Eilers
Sent: Wednesday, December 18, 2002 3:42 PM

Yes, I understand that in Ada as it currently exists, a with clause
on child unit implicitly creates a dependency on its parent.
But this is because the child unit itself implicitly depends on
its parent.  My proposal was to break this implicit dependence
between a child unit and its parent (using a tick mark to distinguish).
Once that dependence is broken, it is perfectly fine to "with" a
child unit without also implicitly "with"-ing its parent.

I proposed retaining the dotted notation in the with clause, but
maybe using the tick mark in the with clause would make it more
clear to the reader and the compiler that there is no implicit
dependence on the child's parent.

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

From: Jean-Pierre Rosen
Sent: Thursday, December 19, 2002 1:41 AM

From: "Robert A Duff" <bobduff@TheWorld.com>
> But you can't "with" a child unit without also "with"-ing its parent.
> Clients need to depend upon the type stubs without depending on the
> "real" type.

Of course you can:
with parent.child
package Parent_Child renames parent.child;

with Parent_Child;  -- No dependence to  Parent
....

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

From: Robert A. Duff
Sent: Thursday, December 19, 2002 10:39 AM

Semantic dependence is transitive (10.1.1(26)), so the above comment is
not correct.  And from an implementation point of view, it has to be
that way, because names in the "...." unit can refer into the symbol
table of Parent.

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

From: Robert Dewar
Sent: Friday, December 20, 2002 5:54 PM

Most certainly correct, nevertheless, JPR's renaming is interesting in that
it shows you can have visibility of the child without visibility of the
parent if I understand things correctly.

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

From: Robert A. Duff
Sent: Friday, December 20, 2002 8:04 PM

Yes, quite true.  But you can still access things that are not directly
visible:

    package Parent is
        subtype S1 is Integer;
        subtype S2 is Integer;
    end Parent;

    package Parent.Child is
        X: S1;
        Y: S2;
    end Parent.Child;

    with Parent.Child;
    package Mumble renames Parent.Child;

    with Mumble;
    procedure Main is
    begin
        Mumble.X := Mumble.Y;

Clearly the compiler needs to know about Parent in order to check
whether the above assignment is legal (and to generate code for it).
The name Parent is not visible in Main, but Main still semantically
depends upon Parent.

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

From: Gary Dismukes
Sent: Wednesday, December 18, 2002 5:19 PM

> I agree completely. Indeed, I was going to do just that if no one else beat
> me to it: create an alternative 5 that's the same as alternative 4 with the
> addition of this syntax (including the wording), and then we can choose
> between them.
> ...
> Syntax-wise, I think I like Bob Duff's original suggestion (way back at 8am
> yesterday) of
>     with separate P;
> which, as Dan points out, will need a private option:
>     [private] with separate P;

I'm in favor of that basic approach as well, with exact syntax deserving
of a little more (e-mail) discussion.  I can also see some merit in Mike
Yoder's suggestion (with type in ...) since it indicates that it's the
types that are of interest from the named package(s).

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

From: Erhard Ploedereder
Sent: Wednesday, December 18, 2002 5:37 PM

My initial reaction was/is to stick with the AI as is. (And I think I can
make it the German reaction at WG9.)

I believe we were blindsided at the meeting by nothing more than a gut
reaction by the users who had all but 10 minutes to get familiar with
the model.

In terms of argument, consider:
  with XYZ; -- creates a semantic dependence
  with private ABC; -- creates a semantic dependence
  with funnykeyword PKG; -- does not create a semantic dependence

What kind of semantic consistency is that ??

And what benefit by the added with-clause (without other changes) ?
The following two lines are semantically equivalent (I hope):
(1)  with funnykeyword PKG;
(2)  -- with funnykeyword PKG;

Based on that, I believe that adding a with clause should be rejected.

---------- but if people do insist on a change....

I can't resist adding a proposal for another context_item
 from GHL use type T; -- does not create a semantic dependence on GHL;
                      -- allows "T" and "GHL.T" in places were the names
                      -- of incomplete types are allowed; etc., etc.
                      -- regarding completion checks

 and then revoke the syntax change to incomplete type decls.
 (Note that this also happens to allow for a solution of the problem
  of equal names, if instead only "GHL.T" is allowed.)

 Compared to the current solution, one loses the ability to "export" the
 incomplete type, but that may be a good thing, anyway.

For now, I would insist that whatever syntax is invented, it not start
with a "with".

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

From: Robert Dewar
Sent: Wednesday, December 18, 2002 5:40 PM

> > The feeling that I got from the discussion of 217 (John, Tucker, Jean-Pierre
> > and maybe some others on this list were there so they can correct me if they
> > disagree) was that a number of individuals strongly felt that a lack of
> > something on the context clause was a violation of Ada design principles.

Count me among this "number of individuals" :-)

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

From: Erhard Ploedereder
Sent: Wednesday, December 18, 2002 5:59 PM

> Syntax-wise, I think I like Bob Duff's original suggestion (way back at 8am
> yesterday) of
>     with separate P;
> which, as Dan points out, will need a private option:
>     [private] with separate P;

Please DON'T, since this comes close to mixing properties of P (which we are
not supposed to depend on) into the semantics of the clause, doesn't it?

Which gives me yet another argument against the "with"-clause strategy...
   private package Parent.Daughter is
        type T is....
   end Parent.Daughter;

   package Parent.Son is
        type T2 is....
   end Parent.Son;

   with separate Parent.Son;  -- ok
   with separate Parent.Daughter; -- is this ok ??? for normal "with" it isn't.
   package foo is

Or have we uncovered a bug in the original AI here, making it possible
to violate privacy of private child packages ? (At first glance, I don't
think so, because ops on the type are subject to visibility.)

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

From: Randy Brukardt
Sent: Wednesday, December 18, 2002 6:43 PM

As you say, "with Parent.Daughter;" is illegal in Ada 95. That's the problem
that "private" with is intending to fix. "private with Parent.Daughter;" is
legal.

So I would say that "with separate Parent.Daughter;" ought to be illegal as
well. But you are right, we don't have any way to tell that (no dependency
on the unit). So we can't make it illegal.

> Or have we uncovered a bug in the original AI here, making it possible
> to violate privacy of private child packages ? (At first glance, I don't
> think so, because ops on the type are subject to visibility.)

I think that you may be right, that AI-217 has a problem here.

    package Foo is
        type T is separate in Parent.Daughter;
    end Foo;

seems to be legal. And it essentially allows Parent.Daughter.T to be
accessed in unrelated packages. OTOH, I don't think you can do anything
useful with it (because, as you say, you don't have visibility on the full
definition unless you can give a context clause for Parent.Daughter). Still
it seems like exporting something that you can't legitimately have access
on.

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

From: Robert Dewar
Sent: Wednesday, December 18, 2002 8:19 PM

> This seems like, how does that saying go, "perfection is the enemy of
> the good", or something like that?  Technically, the objection is right:
> there *should* be some mention of that package in the context clause.
> But from a practical point of view:  As an Ada user, I've been waiting
> desperately for a solution to this serious language flaw for 7 years.
> We've finally got a solution that works, and now folks want to hold it
> up for perhaps another year or more to solve a relatively minor problem?
> Grrr.

I strongly object to any rushing here. The fact of the matter is that
the WG9 approving an AI does not change the standard and suddently require
all compiler writers to go out and implement a feature anyway, we are
possibly talking about a new version of Ada for 2005, that vendors may
or may not implement at that time.

If you want to add some feature to your compiler before there is a new
standard feel free, but it is absolutely not acceptable to rush anything.
There is simply nothing that urgent.

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

From: Robert Dewar
Sent: Wednesday, December 18, 2002 8:28 PM

> Well, I think that's wrong. Tucker already implemented a version of it in
> their compiler. I've been planning to do so as soon as I get some time,
> because it is badly needed to fix some structure problems in the Claw GUI
> Builder. I thought Pascal had indicated that they would be doing it soon. So
> there does seem to be some "rush to implement it"

Anyone is free to implement anything, and indeed trial implementations
are useful. For GNAT, we find our implementation of with type good enough
for now.

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

From: Robert Dewar
Sent: Wednesday, December 18, 2002 8:55 PM

> I completely disagree with this analysis.
>
> First, any time spent by the ARG on 217 is time that is not spent on other
> AIs.  So the question is as usual one of opportunity cost: what AIs are
> currently on the table that we want to bury for the sole purpose of
> marginally improving 217?

But if we go to WG9 and say "well this is not perfect, and it could be
improved, but we are in a hurry and don't have time to do it right." I
think the result will be that WG9 rejects it. That won't save time!

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

From: Robert Dewar
Sent: Wednesday, December 18, 2002 8:56 PM

> > There seems to be a potential orthogonality with AI 262

do you mean non-orthogonality here?

Orthonogal features are ones that do not interact in a negative way (the
terms was introduced I think perhaps by Bauer in the context of the Algol-68
design).

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

From: Ben Brosgol
Sent: Wednesday, December 18, 2002 11:51 PM

> ---------- but if people do insist on a change....
... snip ...
> For now, I would insist that whatever syntax is invented, it not start
> with a "with".

How about:

   for type goto P;

or maybe more seriously:

   at P;

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

From: Pascal Leroy
Sent: Thursday, December 19, 2002 1:41 AM

> ---------- but if people do insist on a change....
>
> I can't resist adding a proposal for another context_item
>  from GHL use type T; -- does not create a semantic dependence on GHL;
>                       -- allows "T" and "GHL.T" in places
> were the names
>                       -- of incomplete types are allowed; etc., etc.
>                       -- regarding completion checks
>
>  and then revoke the syntax change to incomplete type decls.
>  (Note that this also happens to allow for a solution of the problem
>   of equal names, if instead only "GHL.T" is allowed.)

Can you explain to me how this differs from the original "with type"
proposal?  I may be missing something, but I see no point in resurrecting
proposals that have been discussed ad nauseam and discarded for good
reasons.

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

From: Tucker Taft
Sent: Thursday, December 19, 2002 8:43 AM

Robert Dewar wrote:
>>>There seems to be a potential orthogonality with AI 262
>>
>
> do you mean non-orthogonality here?
>
> Orthonogal features are ones that do not interact in a negative way (the
> terms was introduced I think perhaps by Bauer in the context of the Algol-68
> design).

The "orthogonality" that comes to my mind based
on Dan's statement is as follows:

If "private with X;" makes the with clause
only applicable in the private part, then
"separate with X;" make the with clause only
applicable in type stubs.  And I suppose
"private separate with X;" makes the with clause
only applicable in type stubs in the private part.

 From a syntax point of view, if we have gotten
used to the idea of "private with ..." I would
recommend we stick with putting the qualifier
at the front of the with clause, so as implied
above I recommend the syntax be:

    [private] [separate] with library_unit_name {, library_unit_name};

I am also intrigued by Dan's 'Interface suggestion
which is very similar to the package "abstract"
proposal, but...

The biggest problem I have is keeping straight
in my mind the various difficulties associated
with each of the alternative proposals we have
considered.  Pascal reminded me of a few.  Here are
some ones I can remember:

1) Problems with package abstracts
    a) New kind of compilation unit could be major disruption to tools
    b) Not clear what kinds of declarations may
       appear in package abstract
    c) Must everything be repeated in package spec, or is
       package abstract just a prefix on the package spec?
    d) Not obvious in package spec whether package abstract
       does or does not exist (bad memories of optional package bodies
       and optional subprogram specs)

2) Problems with with-type
    a) Want to share access type, but no way to import
       various rep clauses
    b) Context clause visibility is not transitive, so
       this complicates type compatibility rules
    c) Renaming created type compatibility snafoos

3) Problems with type stubs
    a) Nothing in context clause to signal presence of stub.
    b) Doesn't work as well when all types have the same simple name
        (e.g. type Object is ...)

I'm sure there were others.  It would be nice to have a
well-specified list of these problems, with possible solutions
suggested, and then we might be able to make a rational
selection among them.

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

From: Erhard Ploedereder
Sent: Thursday, December 19, 2002 10:20 AM

I can add:

  4) Problems with "full decl identifies stub":
      a) there can be multiple stubs for the same full decl
         (should be supported; but even if declared illegal,
          seems rather difficult to check)
      b) there may be erroneously multiple full decls for a
         single stub (must be illegal, but not easy to check)
      c) would presumably run afoul the same critique, in even
         worse ways, as the "type stub identifies pkg" model.

And I believe I can add a "solution" to problem 2 a), as outlined earlier in
another message:
      The thus "postulated" type is to be treated as an incomplete type,
      so properties of the full type are irrelevant.

All proposals that resort to the incomplete type model share the problem
of incompatible access types formed over multiple views of the type.
(Possible solution lies in user-namable anonymous access types. :-)

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

From: Erhard Ploedereder
Sent: Thursday, December 19, 2002 10:49 AM

>  from GHL use type T; -- does not create a semantic dependence on GHL;
>                       -- allows "T" and "GHL.T" in places
> were the names
>                       -- of incomplete types are allowed; etc., etc.
>                       -- regarding completion checks

> Can you explain to me how this differs from the original "with type"
> proposal?  I may be missing something, but I see no point in ...

While "with type" tried to import full-fledged access types, this one
makes the imported type incomplete, and hence representation is irrelevant.

For all intents and purposes, all I did was to move the incomplete type
decl into the context clause. Apart from the difference that now no name
for the incomplete type is exported anymore (which I consider an advantage
to prevent the "poisoning" of other modules with incomplete types -- if
they want it, they can import it, too), and the possibility of solving
the homograph problem, it is semantically not different from the type
stub model.

As to problems, using Tuck's list for "with type":
    a) Want to share access type, but no way to import
       various rep clauses
       -- no problem, since we do not import access types as such
    b) Context clause visibility is not transitive, so
       this complicates type compatibility rules
       -- This problem remains and could be solved by a rule that
          "pgk.T = pkg.T" (presuming one goes the route of mandating
          selected notation). Not a nice rule, since text-based. Allowing
          both "T" and "pkg.T" is rather deadly in this regard.
    c) Renaming created type compatibility snafoos
       -- none such allowed, since you can't subtype incomplete types

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

From: Erhard Ploedereder
Sent: Thursday, December 19, 2002 10:50 AM

On the context clause proposal, I have yet another syntax:
    "not with P;"
:-)

This nicely expresses the fact that no dependency is formed and yet the
package has been mentioned as desired.

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

From: Robert A. Duff
Sent: Thursday, December 19, 2002 10:55 AM

Tucker wrote:

>     [private] [separate] with library_unit_name {, library_unit_name};

That makes sense.

> 3) Problems with type stubs
>     a) Nothing in context clause to signal presence of stub.
>     b) Doesn't work as well when all types have the same simple name
>         (e.g. type Object is ...)
>
> I'm sure there were others.  It would be nice to have a
> well-specified list of these problems,

Isn't that information in the AI's?

>... with possible solutions
> suggested, and then we might be able to make a rational
> selection among them.

I was under the impression that we have already done that,
and concluded that type stubs are the best solution.
So I suggest we address the above problems, and be done with it:

3 a) Add "separate with lib_unit" syntax as above, and a single legality
rule.  Change the wording about with clauses, so this new kind doesn't
cause semantic dependence.

3 b) The suggested coding style does not have this problem,
so it's not a real problem.  The AI should point this out.

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

From: Pascal Leroy
Sent: Thursday, December 19, 2002 11:23 AM

> I was under the impression that we have already done that,
> and concluded that type stubs are the best solution.
> So I suggest we address the above problems, and be done with it:
>
> 3 a) Add "separate with lib_unit" syntax as above, and a
> single legality
> rule.  Change the wording about with clauses, so this new kind doesn't
> cause semantic dependence.
>
> 3 b) The suggested coding style does not have this problem,
> so it's not a real problem.  The AI should point this out.

I like that approach and I would hope that we could go that way.
Unfortunately, many people in this discussion seem to want to reopen old
cans of worms.

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

From: Dan Eilers
Sent: Thursday, December 19, 2002 11:45 AM

I think it's fair to say that we have pretty conclusively ruled
out "with type" and "package abstracts" as originally proposed,
and are focused on variations of type stubs.

"With type" is simple to implement, but doesn't give full
needed functionality.

"package abstracts" are clean from a user perspective,
but are too heavy (new type of compilation unit, new type
of with clause).

The issue of type stubs came up for reconsideration as the
result of valid WG9 concerns that it goes against Ada design
principles to reference an unknown  package in a type stub.

One solution to the WG9 concern is to weigh down the type-stub
proposal with a new sort of with-clause.  But this is heavy,
and was one of the main reasons for shooting down package abstracts.
It's even heavier than originally thought, due to orthogonality
concerns with the private-with proposal.

To lighten the amended type-stub proposal, there have been at least
two suggestions that haven't been previously considered, and that
haven't yet been shot down:

1) Erhard's proposal that the type stub may not be needed/wanted
if you essentially move it to the context clause.

2) My proposal that the new with-clause isn't needed if you relax
the rule about child units always implicitly depending on their
parents.  (This gets the user benefits of package abstracts without
the heaviness of adding a new type of compilation unit or new
with clause.)

So I don't agree that the type-stub issue is closed yet.

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

From: Tucker Taft
Sent: Thursday, December 19, 2002 12:42 AM

>>I'm sure there were others.  It would be nice to have a
>>well-specified list of these problems,
>
>
> Isn't that information in the AI's?

Yes, I presume it is there.  My problem is keeping
it all in my head at one time, so that I don't
swing wildly from one idea to another just because
I forgot all the problems with each alternative.
Getting them all centralized into a single cohesive
list would certainly help me.  The information in
the AIs is a bit too spread out.

>>... with possible solutions
>>suggested, and then we might be able to make a rational
>>selection among them.
>
>
> I was under the impression that we have already done that,
> and concluded that type stubs are the best solution.

Well, Erhard originally suggested the type stub, I believe, but
he seems to be looking more favorably on something
closer to "with type" now.  It may be that by
recommending the "_Interface" package idiom if there is a
need to declare a shared access type, the "with-type"
which only allows incomplete types (which I think is
all the final version did) is worth reconsidering.

One advantage of the "with type" is that it is *not*
transitive, and it requires use of the full expanded
name of the type, rather than only providing for use
of a simple name.  I think if we disallow mentioning
renamed packages in a with-type clause, it is essentially
equivalent to the type stub, but solves both problems
associated with the type stub (context clause visibility,
and "type Object is...").

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

From: Erhard Ploedereder
Sent: Thursday, December 19, 2002 11:45 AM

> Well, Erhard originally suggested the type stub, I believe, but
> he seems to be looking more favorably on something
> closer to "with type" now.

Actually, I am still in favor of the AI as written. But I am trying
to swing with the punches, seeing that the ARG is being swayed, too,
by the "must be part of context clauses" attitude. And getting the
"type Object"-Problem solved alongside, well....

(I definitely do not want to see the abstract package solution. That
 one is way too heavy.)

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

From: Pascal Leroy
Sent: Thursday, December 19, 2002 11:30 AM

> > Can you explain to me how this differs from the original "with type"
> > proposal?  I may be missing something, but I see no point in ...
>
> While "with type" tried to import full-fledged access types, this one
> makes the imported type incomplete, and hence representation
> is irrelevant.

When we discussed the "with type" idea a long time ago (I think it was at
the Intermetrics meeting) the general feeling was that a mechanism for
importing access types was fundamentally important.  Otherwise you have to
have multiple access types, and you end up with explicit conversions between
access types everywhere in your code.  So much for the legendary readability
of Ada!  And don't tell me that anonymous-access-types-everywhere solve that
problem, because that AI (230, as I recall) is fraught with difficulties and
would be awfully disruptive for compilers.

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

From: Randy Brukardt
Sent: Thursday, December 19, 2002 6:10 PM

> The biggest problem I have is keeping straight
> in my mind the various difficulties associated
> with each of the alternative proposals we have
> considered.  Pascal reminded me of a few.  Here are
> some ones I can remember:

Here is the list I sent in July 2001 [found in the Appendix to alternative
3]. (We hadn't invented the current proposal at that time):

    "with type"
        Con: Can't handle access types (due to representation issues).
             Implementation needs "pseudo packages" internally.
             What happens when multiple paths to the same item "meet"?
        Pro: Easy to describe to users.
    "package abstract"
        Con: Heavy, complex mechanism. Complex visibility issues to work out.
             New kind of compilation unit affects all tools (alternatives
             avoiding compilation unit has similar effect on tools because the
             source must be compiled in two different ways).
        Pro: Handles access types cleanly.
    "type separate"
        Con: Must introduce extra packages (either "unnecessary" parents with
             Tucker's rules or "unrelated" ones with Dan's/Randy's rules).
             No allocators/deallocators on access types with designated types
             of this kind.
             (Probably others, once a proposal is made and picked apart.)
        Pro: No new kind of units. No new visibility issues. Access types can
             be handled (representation clauses can be given if needed). Model
             is easy to understand (it is an extension of existing rules). No
             run-time implementation problems; the implementation is identical
             to incomplete-completed-in-body.

Comparing this to Tucker's list, they appear to be pretty much the same, so
I think we can safely just use his list.

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

From: Tucker Taft
Sent: Thursday, December 19, 2002 8:35 PM

Well I went back and reread both the "with type"
and the "type xxx is separate..." proposals, and
it really seems like if we are willing to use
the rules of "type XXX is separate ..." but with
the syntax of "with type ..." we get the best
of both worlds.

In particular, much of the complexity
of "with type ..." came from trying to support
references to package renamings.  If we simply disallow
that, we can treat the enclosing package name roughly like
a string literal, and not worry about it until a point where
we need a full type.  At that point we have to make
sure that the enclosing package has been "with"ed.
The matching rules given in the type stub proposal
could be used directly.  The access type concerns
associated with "with type" are no worse than
the type stub, since both can only be used to introduce
an incomplete type.  If you want a shared access type,
then you create an _Interface (or _Pointers) package, and
declare the access type there.

I would disallow subtypes of the incomplete types (as is
disallowed for incomplete types now), and disallow
renamings of packages whose names are mentioned only
in "with type" clauses.

The rule given in the type-stub proposal for when the
full type must be visible would work for the "with type"
proposal just as well.

Hence, I would propose that we go back to the
with-type proposal, with semantic rules taken
in large part from the type-stub proposal.

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

From: Pascal Leroy
Sent: Thursday, December 19, 2002 11:43 PM

> > I thought Pascal had indicated that they would be doing it soon. So
> > there does seem to be some "rush to implement it"
>
> Anyone is free to implement anything, and indeed trial implementations
> are useful. For GNAT, we find our implementation of with type
> good enough for now.

My company is not interested in implementing experimental features for the
fun of it, because that's not what our customers want.  They want features
that solve their problems, will be supported over the next 10 years, and
will be portable to other compilers.  An endorsement by WG9 is (short of the
production of a TC or an Amendment) a good indication that a proposed
feature is likely to be supported by a variety of compilers over long
periods of time.

We have seen a lot of demand for a solution to the problem of mutually
dependent types in the 95-98 timeframe, because people were under the
impression that with Ada 95 they would be able to easily map UML models to
Ada.  That particular issue came up a lot, and was a nightmare in real
projects.  Since then the pressure has diminished, either because people
have somehow circumvented the problem, or because they have moved to a
language that supports mutually dependent types.

Wait another year and we will have reached the point where it's impossible
to make a business case for implementing type stubs.

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

From: Pascal Leroy
Sent: Friday, December 20, 2002 1:48 AM

> Well I went back and reread both the "with type"
> and the "type xxx is separate..." proposals, and
> it really seems like if we are willing to use
> the rules of "type XXX is separate ..." but with
> the syntax of "with type ..." we get the best
> of both worlds.

I am really annoyed that we are reopening the "with type" proposal, because
there were many technical difficulties associated with it which I suppose we
are going to re-discover.  At some point in time we at Rational made a
detailed design of how this could be implemented in our compiler, and came
up with two very significant problems:

1 - In order to implement "with type" the compiler would have to build
hidden package declarations to hold the incomplete types.  The reason is
that throughout the compiler we are making the assumption that types
(incomplete or not) are only declared in declarative parts, not in the
middle of context clauses, and hidden packages seem the best solution to
avoid breaking this assumption.  Interestingly enough I remember discussing
this with Tucker privately during the Leuven meeting, and at the time
Averstar had started a design too, and they had come with the exact same
mechanism.  This is in fact what led to the "package abstract" proposal: the
minutes of the Leuven meeting have the following paragraph:

"Tucker would like to abandon the with type proposal. He says it is
misguided, because you have to posit the existence of "ghost" or
"incomplete" packages to describe it. In other words, a compiler will need
to create a hidden package specification, and populate it with the right
stuff. Then it is possible to see a lot of these ghost packages, which
provide different views of the same package, and the compiler must figure
out that they all correspond."

2 - The consistency check between the incomplete type declaration(s) and the
completion is practically impossible to implement for a compiler doing
incremental compilation.  The "with type" AI has the rule:

"Any compilation unit that has a semantic dependence on another compilation
unit which has a "with_type_clause," as well as a dependence on the package
identified by the with_type_clause, must verify that a type declaration (not
just a subtype declaration) for the named type does in fact appear within
the visible part of the package."

But this means that the addition of a with clause (either a normal one or a
"with type") can change the location where the consistency check has to be
performed.  Similarly for the removal of an otherwise unused with clause.
The impact analysis phase of our compiler would have to remember the entire
dependency graph, and determine if, because of incremental changes, the
locations where the check is made change.  If so, it would have to obsolesce
the appropriate units.  Not only is that awfully complicated, but it has a
complexity which is proportional to the size of the entire program, not to
the size of the change, so it essentially kills incremental compilation.

I believe that this issue illustrates the fact that the non-transitivity of
with clauses is a drawback, not an advantage, of the "with type" model.

> In particular, much of the complexity
> of "with type ..." came from trying to support
> references to package renamings.

Curiously, that's not what I remember.  This was only one of the numerous
issues that killed that proposal.

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

From: Tucker Taft
Sent: Friday, December 20, 2002 8:20 AM

> "Tucker would like to abandon the with type proposal. He says it is
> misguided, because you have to posit the existence of "ghost" or
> "incomplete" packages to describe it. In other words, a compiler will need
> to create a hidden package specification, and populate it with the right
> stuff. Then it is possible to see a lot of these ghost packages, which
> provide different views of the same package, and the compiler must figure
> out that they all correspond."

This problem is significantly simplified, I believe, if you
don't allow the use of package renamings in the name of
the with'ed type.


> 2 - The consistency check between the incomplete type declaration(s) and the
> completion is practically impossible to implement for a compiler doing
> incremental compilation.  The "with type" AI has the rule:
>
> "Any compilation unit that has a semantic dependence on another compilation
> unit which has a "with_type_clause," as well as a dependence on the package
> identified by the with_type_clause, must verify that a type declaration (not
> just a subtype declaration) for the named type does in fact appear within
> the visible part of the package."

I suggested we use the rule from the type-stub proposal *instead*
of this rule.  It avoids the problems you had with this one, I believe.

> But this means that the addition of a with clause (either a normal one or a
> "with type") can change the location where the consistency check has to be
> performed.  Similarly for the removal of an otherwise unused with clause.
> The impact analysis phase of our compiler would have to remember the entire
> dependency graph, and determine if, because of incremental changes, the
> locations where the check is made change.  If so, it would have to obsolesce
> the appropriate units.  Not only is that awfully complicated, but it has a
> complexity which is proportional to the size of the entire program, not to
> the size of the change, so it essentially kills incremental compilation.
>
> I believe that this issue illustrates the fact that the non-transitivity of
> with clauses is a drawback, not an advantage, of the "with type" model.
>
>
>>In particular, much of the complexity
>>of "with type ..." came from trying to support
>>references to package renamings.
>
>
> Curiously, that's not what I remember.  This was only one of the numerous
> issues that killed that proposal.

In any case, if these are significant problems with the with-type,
then they need to be put into our "concise" list of pros/cons.
Somehow I missed them, and I believe Randy did as well.

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

From: Erhard Ploedereder
Sent: Friday, December 20, 2002 8:33 AM

> When we discussed the "with type" idea a long time ago (I think it was at
> the Intermetrics meeting) the general feeling was that a mechanism for
> importing access types was fundamentally important.

Type stubs in any of the proposed forms don't give you that capability
either, directly. It is an unsolvable problem, given the statement that
access types might vary in representation. You then need to resort to
the _Pointers package in any of the proposed models (unless we get the
pointer compatibility problem solved, too, as part of another AI).

As to Tuck's model in the message that starts:
> Well I went back and reread both the "with type"

Yes. That's exactly the model that I had in mind, too.

> disallow renamings of packages whose names are mentioned only
> in "with type" clauses.

needs some ...smithing, though, since you can't have retroactive
illegality of past renamings. It looks solvable, though, by simply
not allowing for completion of types taken from renamed packages.

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

From: Erhard Ploedereder
Sent: Friday, December 20, 2002 11:59 AM

> I am really annoyed that we are reopening the "with type" proposal, because
> there were many technical difficulties associated with it which I suppose we
> are going to re-discover.

This is turning into a red herring, because I am fairly sure that any
problem that might be discovered for the Tucker/my model is equally
present in the type stub proposal as written or as amended with the
vacuous context clause that merely names the package.

Put differently: if we re-discover a problem, we almost certainly have
the same problem with the type stub proposal and merely haven't realized
it.

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

From: Robert Dewar
Sent: Friday, December 20, 2002 9:28 PM

> Hence, I would propose that we go back to the
> with-type proposal, with semantic rules taken
> in large part from the type-stub proposal.

At first glance, I certainly like that approach.

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

From: Robert Dewar
Sent: Friday, December 20, 2002 9:32 PM

> My company is not interested in implementing experimental features for the
> fun of it, because that's not what our customers want.  They want features
> that solve their problems, will be supported over the next 10 years, and
> will be portable to other compilers.  An endorsement by WG9 is (short of the
> production of a TC or an Amendment) a good indication that a proposed
> feature is likely to be supported by a variety of compilers over long
> periods of time.

Well I don't share your view that an endorsement of an AI is a guarantee
of longevity ...

> Wait another year and we will have reached the point where it's impossible
> to make a business case for implementing type stubs.

This seems a very specific and peculiar situation (peculiar to you), I am
not sure that it constitutes a valid argument for rushing.

The fact of the matter is that no one can expect to get an immediate ruling
on a permanent solution to this problem. I actually think that some
experimental implementations would be useful.

I know we have several customers using "with type" to solve at least some
of these problems. I am not aware of any significant feedback, negative
or positive. Perhaps we should try to poll our customer base and get that
feedback.

P.S. I quite understand the concerns with the model that we implemented.
Note that at the time we implemented it, it seems quite likely that it
would be adopted and "be supported over the next 10 years etc" :-)

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

From: Robert Dewar
Sent: Friday, December 20, 2002 9:36 PM

Note incidentally that my concern about rushing is precisely that I do NOT
want another false step here. At a previous point in time, everyone seemed
quite happy with the original "with type" proposal, but it was *NOT*
rushed "into production", and sure enough problems were found. It is
really important this time to get things right. Rushing for WG9 approval,
which then has later to be reconsidered because further problems are
found does not do any one any good.

Pascal, if you really *do* think that you have your hands on a fine proposal,
I would encourage you to implement it. In fact arguments based on actual
successful usage are very powerful ones.

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

From: Pascal Leroy
Sent: Saturday, December 21, 2002 10:41 AM

> > "Tucker would like to abandon the with type proposal. He says it is
> > misguided, because you have to posit the existence of "ghost" or
> > "incomplete" packages to describe it. In other words, a compiler will need
> > to create a hidden package specification, and populate it with the right
> > stuff. Then it is possible to see a lot of these ghost packages, which
> > provide different views of the same package, and the compiler must figure
> > out that they all correspond."
>
> This problem is significantly simplified, I believe, if you
> don't allow the use of package renamings in the name of
> the with'ed type.

I don't think so.  In the case of our technology at least, the problem we
had was that the "with type" construct was a very odd beast.  In many places
we have code that assumes that a type is declared by a bona-fide type
declaration, living in a bona-fide declarative part.  The "with type" didn't
fit that pattern.  That's why we came to the conclusion that we had to
create these "ghost" packages to go back to a model (type declaration in
declarative part) that we were prepared to handle.

I realize that this may just reflect a limitation of our technology, but I
am always uncomfortable when the compiler has to go through hoops to
implement a feature.  (We have similar difficulties with children of
generics, and they are not the most natural feature of Ada 95 if you ask
me.)

The more I think of it the less I like the "with type" proposal.  To me, the
context clauses are for "importing" stuff from other units.  Now don't tell
me that "with type" imports a type, because that type may not even exist yet
(I guess I am echoing Erhard's discomfort at having a with clause that
doesn't involve a semantic dependency).  The "with type" really declares an
incomplete type, but then the normal place where type declarations occur are
visible/private parts.  So I think it's much more WYSIWYG to place that
declaration in the package (like type stubs do) than in the context clauses
(like "with type" does).

> > "Any compilation unit that has a semantic dependence on another compilation
> > unit which has a "with_type_clause," as well as a dependence on the package
> > identified by the with_type_clause, must verify that a type declaration (not
> > just a subtype declaration) for the named type does in fact appear within
> > the visible part of the package."
>
> I suggested we use the rule from the type-stub proposal *instead*
> of this rule.  It avoids the problems you had with this one,
> I believe.

I missed that part of your proposal.  Then I agree, it doesn't cause trouble
with incremental compilation.

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

From: Pascal Leroy
Sent: Saturday, December 21, 2002 10:50 AM

> Pascal, if you really *do* think that you have your hands on a fine proposal,
> I would encourage you to implement it. In fact arguments based on actual
> successful usage are very powerful ones.

Well, I really do think that the type stubs AI as recently sent to WG9 was a
fine proposal, and I don't believe that any actual flaw has been found in
it.  What I hear is a number of people saying that they don't like it for a
variety of aesthetical reasons, but I don't think that any technical problem
has been found in it.

As for implementing it, unfortunately it's not my decision, and I don't see
this happening without a WG9 endorsement.

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

From: Ed Schonberg
Sent: Saturday, December 21, 2002 11:27 AM

The two technical problems with type stubs:

>  3) Problems with type stubs
>      a) Nothing in context clause to signal presence of stub.
>      b) Doesn't work as well when all types have the same simple name
>          (e.g. type Object is ...)

seem simpler to solve than the semantic difficulties of "with type".

Concerning b), the syntax of an incomplete type declaration could include:

    type  P.T;    --  stub name is an expanded name.

which is more terse (terser?) that the "separate in" syntax. Subsequent
references are of course forced to use the expanded name as well.

Concerning a), we could state a rule similar to 10.1.5 (6) for program
unit pragmas: "a type stub declaration shall appear before any other
nested declarations". This places them as close to the context as
possible. This is easy to state and possibly to swallow (even though it
it is reminiscent of the Ada83 annoying restrictions on order of
declarations).

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

From: Randy Brukardt
Sent: Saturday, December 21, 2002 1:01 PM

Ed Schoenberg wrote:

> The two technical problems with type stubs:
>
> >  3) Problems with type stubs
> >      a) Nothing in context clause to signal presence of stub.
> >      b) Doesn't work as well when all types have the same simple name
> >          (e.g. type Object is ...)
>
> seem simpler to solve than the semantic difficulties of "with type".

True. But we made a technical decision not to solve b). Certainly the
proposed solution of
    type Obj is separate in P.T;
is simple and straightforward. And it has the advantage of making everything
explicit; Ada is about readability, not ease of writing after all. But it
was defeated in a straw poll.

> Concerning b), the syntax of an incomplete type declaration
> could include:
>
>     type  P.T;    --  stub name is an expanded name.
>
> which is more terse (terser?) that the "separate in" syntax. Subsequent
> references are of course forced to use the expanded name as well.

I don't like this for two reasons:
* It is not at all clear that this is a stub declaration. We usually favor
readability in Ada, not cutting the number of characters.
* It requires changing the syntax of type declarations, as they only take
identifiers currently. That is the main reason alternative 3 was rejected
(explicit completion).
* It brings back all of the ugliness of "ghost" packages. In Janus/Ada, the
only way for there to be something called P.T is for there to be a program
unit called P. But then we have to prevent direct use of P by itself, so a
lot of extra code has to be added all over the place. Indeed, we complained
about this in child packages during the U/I project, and the standard was
eventually changed to eliminate it. (I object to expanded names in any "with
type" proposal for the same reasons.)

(OK, that's three reasons).

> Concerning a), we could state a rule similar to 10.1.5 (6) for program
> unit pragmas: "a type stub declaration shall appear before any other
> nested declarations". This places them as close to the context as
> possible. This is easy to state and possibly to swallow (even though it
> it is reminiscent of the Ada83 annoying restrictions on order of
> declarations).

That would prevent using type stubs in private parts. One of the big
advantages of type stubs over the original "with type" is that type stubs
can be made to be private. That let's you declare a handle to them without
exposing the actual access type to the world:

    package PP is
        type Handle is private;

        ...
    private
        type Object is tagged separate in P.T;
        type Handle is access Object'Class;
    end PP;

I think all of the current proposals (both type stub and with type) would
allow private stubs, and I think they are likely to be useful.

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

From: Randy Brukardt
Sent: Saturday, December 21, 2002 1:13 PM

Robert Dewar said:

> Note incidentally that my concern about rushing is precisely that I do NOT
> want another false step here. At a previous point in time, everyone seemed
> quite happy with the original "with type" proposal, but it was *NOT*
> rushed "into production", and sure enough problems were found. It is
> really important this time to get things right. Rushing for WG9 approval,
> which then has later to be reconsidered because further problems are
> found does not do any one any good.

I grudgingly have to admit that Robert's right about rushing. But I also
have to agree with Pascal that there aren't any technical (as opposed to
aesthetic) problems yet found with the type stub proposal.

> Pascal, if you really *do* think that you have your hands on a fine proposal,
> I would encourage you to implement it. In fact arguments based on actual
> successful usage are very powerful ones.

The problem with that is we need a fairly stable solution before trial
implementations make sense. If we continue to wildly toss about solutions
that aren't remotely similar, then an implementation really doesn't help,
because it probably will have little in common with the final solution.
That's the problem with GNAT's with type, for instance.

The Ada 9x User/Implementor teams didn't spend that much time on proposals
that weren't pretty firm. I think more than 80% of our U/I code is still in
Janus/Ada. Proposals like finalization and streams which were all over the
place until the last minute never got implemented by any of the U/I teams.
Not surprisingly, those also are the proposals with the most problems that
we've had to fix in the standard.

Because of the last factor, and the high importance of this issue, I think
it is imperative that we settle on the basic outline of the solution, so
that we can get some early implementations to ferret out problems. (In this
case, I'm concerned about the complexity of the type matching rules, which
would be essentially the same in type stubs or in with type v. 2.) If we
continue to be all over the place, we may eventually freeze a solution, but
then we'll end up spending a lot of time patching it up in the next five
years.

So my preference is to stop dreaming up new ideas (because they really don't
add much, if anything) and figure out what, if anything, we need to do to
make the proposal we have better.

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

From: Robert Dewar
Sent: Saturday, December 21, 2002 1:20 PM

> The more I think of it the less I like the "with type" proposal.  To me, the
> context clauses are for "importing" stuff from other units.  Now don't tell
> me that "with type" imports a type, because that type may not even exist yet
> (I guess I am echoing Erhard's discomfort at having a with clause that
> doesn't involve a semantic dependency).  The "with type" really declares an
> incomplete type, but then the normal place where type declarations occur are
> visible/private parts.  So I think it's much more WYSIWYG to place that
> declaration in the package (like type stubs do) than in the context clauses
> (like "with type" does).

I think this is too much of an implementation viewpoint. The context clause
shows dependencies in the sense of program design, i.e. the meaning of a unit
depends on other units at a conceptual level. The "with type" most certainly
does say that this unit is dependent on stuff in another unit from a point
of view ot semantic understanding. To me it seems quite natural. I really
don't mind the exact form, but it seems essential to me that this kind
of conceptual "dependence" be represented in the context clause.

I want to emphasize here that as far as GNAT and ACT goes, the chocie is
neutral, we don't see any particular conceptual difficulties in implementing
any of these schemes. To properly complete our existing with type
implementation is not likely to be significantly easier than full
implementation of any of the schemes under discussion.

So my concerns here, unlike Pascal's, are not at all rooted in concerns
about difficulty of implementation, but rather on my conceptual feeling
that some indication in the context clause is absolutely essential from
a methodoloogical point of view.

I don't object to taking implementation difficulties into account. There
are only in effect a handful of Ada 95 front end technologies at this stage,
and it is certainly appropriate to listen if any proposal would cause
difficulties, not the least because it would likely be a significant
barrier to eventual WG9 approval of a new standard (after all, we made
very significant compromises in the initial Ada 95 design, based partly
on concerns about difficulties of implementation in technologies that
did not even manage to make the Ada 95 transition after all). However,
I think that such concerns must take a back seat to fundamental
methodological consistency considerations.

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

From: Robert Dewar
Sent: Saturday, December 21, 2002 1:24 PM

> Well, I really do think that the type stubs AI as recently sent to WG9 was a
> fine proposal, and I don't believe that any actual flaw has been found in
> it.  What I hear is a number of people saying that they don't like it for a
> variety of aesthetical reasons, but I don't think that any technical problem
> has been found in it.

Well if I am following things correctly, one objection is the lack of an
indication in the context clause. For me that is much more than an
"aesthetical reason", it is a fundamental flaw, one that would certainly
cause me to recommend that the US delegation vote against the proposal.

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

From: Ed Schonberg
Sent: Saturday, December 21, 2002 1:24 PM

>  > Concerning b), the syntax of an incomplete type declaration
>  > could include:
>  >
>  >     type  P.T;    --  stub name is an expanded name.
>  >
>  > which is more terse (terser?) that the "separate in" syntax. Subsequent
>  > references are of course forced to use the expanded name as well.
>
>  I don't like this for two reasons:
>  * It is not at all clear that this is a stub declaration. We usually favor
>  readability in Ada, not cutting the number of characters.
>  * It requires changing the syntax of type declarations, as they only take
>  identifiers currently. That is the main reason alternative 3 was rejected
>  (explicit completion).

It is a stub declaration precisely because the syntax is not that of a
type declaration. From a parsing point of view it's trivial, and if it is
placed next to the context clause it's even easier to recognize.

>  * It brings back all of the ugliness of "ghost" packages. In Janus/Ada, the
>  only way for there to be something called P.T is for there to be a program
>  unit called P. But then we have to prevent direct use of P by itself, so a
>  lot of extra code has to be added all over the place. Indeed, we complained
>  about this in child packages during the U/I project, and the standard was
>  eventually changed to eliminate it. (I object to expanded names in any "with
>  type" proposal for the same reasons.)

This is semantically no different that the current stubs proposal. Why are
 those "ghost" packages not a problem with stubs?

>  > Concerning a), we could state a rule similar to 10.1.5 (6) for program
>  > unit pragmas: "a type stub declaration shall appear before any other
>  > nested declarations". This places them as close to the context as
>  > possible. This is easy to state and possibly to swallow (even though it
>  > it is reminiscent of the Ada83 annoying restrictions on order of
>  > declarations).

>  That would prevent using type stubs in private parts. One of the big
>  advantages of type stubs over the original "with type" is that type stubs
>  can be made to be private. That let's you declare a handle to them without
>  exposing the actual access type to the world.

Well, the desire to give some context-level indication that these are imported
types is in serious conflict with the desire to hide them! Given that in the
majority of cases these types are introduced in order to define access types
for them, placing the stub in the private part seems to me like a rather
transparent fig leaf. Of the various conflicting requirements here, having
private stubs seems to me the weakest.

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

From: Robert Dewar
Sent: Saturday, December 21, 2002 1:28 PM

> Concerning a), we could state a rule similar to 10.1.5 (6) for program
> unit pragmas: "a type stub declaration shall appear before any other
> nested declarations". This places them as close to the context as
> possible. This is easy to state and possibly to swallow (even though it
> it is reminiscent of the Ada83 annoying restrictions on order of
> declarations).

I really prefer a separate indication in the context clause rather than
this restriction of placement. And I don't see what the big deal is in
introducing this separate indication.

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

From: Randy Brukardt
Sent: Saturday, December 21, 2002 2:40 PM

> >  > Concerning b), the syntax of an incomplete type declaration
> >  > could include:
> >  >
> >  >     type  P.T;    --  stub name is an expanded name.
> >  >
> >  > which is more terse (terser?) that the "separate in" syntax. Subsequent
> >  > references are of course forced to use the expanded name as well.
> >
> >  I don't like this for two reasons:
> >  * It is not at all clear that this is a stub declaration. We usually favor
> >  readability in Ada, not cutting the number of characters.
> >  * It requires changing the syntax of type declarations, as they only take
> >  identifiers currently. That is the main reason alternative 3 was rejected
> >  (explicit completion).
>
> It is a stub declaration precisely because the syntax is not that of a
> type declaration. From a parsing point of view it's trivial, and if it is
> placed next to the context clause it's even easier to recognize.

Huh? It declares a type, so "of course" its a type declaration. The only way
to introduce a type currently is via a type declaration; it seems very
strange to add a new concept that is almost the same.

> >  * It brings back all of the ugliness of "ghost" packages. In Janus/Ada, the
> >  only way for there to be something called P.T is for there to be a program
> >  unit called P. But then we have to prevent direct use of P by itself, so a
> >  lot of extra code has to be added all over the place. Indeed, we complained
> >  about this in child packages during the U/I project, and the standard was
> >  eventually changed to eliminate it. (I object to expanded names in any "with
> >  type" proposal for the same reasons.)
>
> This is semantically no different that the current stubs proposal. Why are
>  those "ghost" packages not a problem with stubs?

Yes it is, because there is no "expanded" name in the current proposal. (the
thing following the "in" is not a name at all -- that is very important,
bother for dependency reasons and for implementation reasons).

"Ghost" packages come up when you have a name "P.T" without a name "P".

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

From: Pascal Leroy
Sent: Sunday, December 22, 2002 4:36 AM

> That let's you declare a handle to them without
> exposing the actual access type to the world:
>
>     package PP is
>         type Handle is private;
>
>         ...
>     private
>         type Object is tagged separate in P.T;
>         type Handle is access Object'Class;
>     end PP;
>
> I think all of the current proposals (both type stub and with type) would
> allow private stubs, and I think they are likely to be useful.

That's an intriguing example when you modify it to include a nested package:

    package QQ is
        package PP is
            type Handle is private;
        private
            type Object is tagged separate in P.T;
            type Handle is access Object'Class;
        end PP;
    end QQ;

With type stubs you can precisely control which regions have visibility over the
incomplete type.  With "with type" the entire unit (with the possible exception
of the visible part) has visibility over it.  I am not claiming that the former
is a superduper important capability, but it certainly seems nicer to me to have
fine visibility control.

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

From: Pascal Leroy
Sent: Monday, December 23, 2002 4:39 AM

 Well if I am following things correctly, one objection is the lack of an
> indication in the context clause. For me that is much more than an
> "aesthetical reason", it is a fundamental flaw, one that would certainly
> cause me to recommend that the US delegation vote against the proposal.

Just to clarify, I am happy with the notion of adding some kind of indication in
the context clause of which units are forward-referenced.  Of all the proposals
that I have seen so far, the one I prefer is Tuck's "[private] [separate] with
P;".  What I object to is the notion of resurrecting "with type" from the dead.

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

From: Randy Brukardt
Sent: Friday, January 17, 2003 8:31 PM

Here's the list of problems that was posted during the previous discussions,
renumbered so that they have the same numbers as the alternatives.

1) Problems with with-type
    a) Want to share access type, but no way to import
       various rep clauses
    b) Context clause visibility is not transitive, so
       this complicates type compatibility rules
    c) Renaming created type compatibility snafus

2) Problems with package abstracts
    a) New kind of compilation unit could be major disruption to tools
    b) Not clear what kinds of declarations may
       appear in package abstract
    c) Must everything be repeated in package spec, or is
       package abstract just a prefix on the package spec?
    d) Not obvious in package spec whether package abstract
       does or does not exist (bad memories of optional package bodies
       and optional subprogram specs)

3) Problems with type stubs with explicit completion
     a) there can be multiple stubs for the same full declaration
        (should be supported; but even if declared illegal,
         seems rather difficult to check)
     b) there may be erroneously multiple full declarations for a
        single stub (must be illegal, but not easy to check)
     c) would presumably run afoul the same critique, in even
        worse ways, as the "type stub identifies package" model.

4) Problems with type stubs with completing package name
    a) Nothing in context clause to signal presence of stub.
    b) Doesn't work as well when all types have the same simple name
        (e.g. type Object is ...)

All) All proposals share:
    a) Incompatible access types formed over multiple views of the type.

--

We don't need to discuss #2 and #3 further, I think. (Well, I don't really
want to discuss any of them again, but since a number of people insisted.
I'm going through this exercise to help motivate alternative #5, which I
shall present shortly).

All (a) is misleading. In the intended use of type stubs, you declare a
single access type in the interface package, and use that everywhere,
including in the spec. of the base package. As in the example in AI-217-04:

   package Employees_Interface is
       type Employee is tagged separate in Employees;
       type Emp_Ptr is access all Employee'Class;
   end Employees_Interface;

   with Employees_Interface, Department_Interface;
   package Employees is
       type Employee is tagged private;
       subtype Emp_Ptr is Employees_Interface.Emp_Ptr;
        procedure Assign_Employee(E : in out Employee;
                                  D : in out
Departments_Interface.Department);
        ...
        function Current_Department(D : in Employee) return
            Departments_Interface.Dept_Ptr;
    end Employees;

Note that the subtype Emp_Ptr re-exports the access type, so that everyone
can use the same type. So problem All (a) is a problem if-and-only-if your
program isn't structured very well. I don't think we should concern
ourselves with that.

Tucker's (virtual) proposal for with types rewrites purports to fix problems
1(a) and 1(c). Clearly problem 1(b) remains. With the rules has Tucker
proposed them, it is impossible to re-export a with type. That means that
every package that needs to use the type will have to import it, even if it
imports everything else from an interfaces package. That seems fundamental
to the proposal.

Tucker's problem list did not include 1(d): Visibility problems and/or ghost
packages required. That is a critical omission, because the solution to it
complicates any with type proposal a lot. The problem is basically that if
you have a name P.T, then you have to do something about when P is used
alone. If P.T is a name, but P is not, then you have greatly complicated the
handling of program unit expanded names, since such a prefix cannot be
ambiguous on its own. In an example like:

package Parent is
    function P return Natural;
end Parent;

with type P.T;
package Parent.Child is

    type Ptr_T is access all P.T;

    C : constant Natural := P; -- Function P?
end Parent.Child;

The visibility of P.T and the parent P get mixed up. Similarly, if someone
writes the rather nonsense:

with P;
with type P.T;

you have to figure out what happens.

Solving this seems to require the introduction of ghost packages.

For me, there is also a 1(e): "with type" is inconsistent with the other
uses of the context clause, and looks like a kludge. Why just "with type"?
Why not "with exception" or "with constant"?? Please don't bring up "use
type": it is precisely an example of what not to do here. The same question
can be asked of it, why not "use constant" or "use exception"? Moreover, it
isn't even "use type"; it's "use operators of type".

Related to that, the items in a with_clause are all program units. Why are
we suddenly adding types? Tuck has previously complained that he doesn't
like the new features to look like add-ons. This one certainly does.

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

From: Randy Brukardt
Sent: Friday, January 17, 2003 8:32 PM

The objections to the with the half-worked out "with separate" clause were
primarily:
   (1) A with_clause that doesn't make a semantic dependence looks
inconsistent;
   (2) Some odd objection against re-exporting these types.

I completely fail to understand (2). I view that as a major, unfixable flaw
of any with type like proposal. Moreover, type stubs allow much better
control over visibility than with type. Ada has often been criticized for
not having fine visibility control on compilation units; I don't see the
appeal of adding more features with that problem.

OTOH, I've come around on the users concerns. When we see a with clause, we
see "semantic dependence". But that's language lawyer talk. Users just see
dependence. It's easy to think of a with_clause as a "strong dependence",
and our new clause (whatever it may be) to be a "weak dependence". I'm
pretty sure that is how people will think of it.

Still, I started thinking about both the solutions to problems 4(a) and
4(b), and 5(1). I wondered if Dan Eilers wasn't on the right track when he
proposed a specially named package to hold these things. After all, problem
3(b) (the multiple names problem) isn't a real problem if you have an
interface package for every type in the system. (And that seems like a good
idea, as it eliminates the multiple access type problem, by providing a
single point of declaration for it.) Dan's proposal:
    package P'Interface is
has some advantages, but the significant disadvantage of a new kind of name.
I'd probably make 'Interface an attribute, rather allow it to be anything,
but that doesn't help much.

So I turned to other ways to look at this. Perhaps a package modifier would
do the trick:

    package P_Interface is interface of P is ...

This worried me because we now have two new proposals, both called
interfaces. (One is interfaces types, and the other is interfaces packages,
but that seems much too easy to confuse.) So I want back to the package
abstract proposal and stole some terminology:

    package P_Abstract is abstract of P is ...

Well, the two "is"s don't look great, and besides, you find out about this
too late. It probably should go in front:

    abstract of P; package P_Abstract is...

And I've arrived back at a new context clause item. However, this one
eliminates Erhard's objection that we'd be adding a with_clause that doesn't
make a semantic dependence. It also doesn't have the naming problems of
"with type" (any version). It also reinforces the intended use of the
feature (and of type stubs). It also doesn't look quite as much like a
kludge, because it is easy to imagine other types of stubs in the future
(constant stubs,
exception stubs, and especially a new kind of subprogram stub). So this
doesn't lock us in like "with type" does.

The model is that this represents an "abstracted package" from which we can
use selected details without making a semantic dependence (a "strong
dependence" as noted above). It would be easy to then call a package having
one of these clauses a "package abstract", but clearly it can contain more
than just the contents of the abstracted package.

Anyway, I've written this up completely (including all of the wording), so we
can see how it plays out. That will be alternative #5, which I'll send in the
next message [This is AI-217-05/01, ED]. Obviously, we can tweak the
terminology or even go back to "with separate" without actually changing much
of the wording, so I hope that this is not wasted effort.

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

From: Robert I. Eachus
Sent: Friday, January 17, 2003 11:18 PM

Part of the reason I haven't been posting for a while was trying to get
my head around this whole issue.  I like the current alternative.  I can
also understand why some people have trouble with the package containing
the type not being mentioned in the context clause.  So far I have come
to two firm conclusions on how to fix this:

1) The name of the package may be required in some context clause, but
putting the type name there leads to trouble.
2) There needs to be an exclusion rule.  Whatever gets added to the
context clause, it must be illegal to have a with clause for the same
package in the context clause.

Point 2 actually starts to make a great deal of sense out of user's
objections.  The context clause is the proper place for context
requirements, and distributing them through the entire specification is
a step in the wrong direction.

Now let me have some Norm Cohen style fun.

use type in Foo;
...
type Bar is separate in Foo;
...

By putting a "use", not a "with" in the context clause, there is no need
to wrap our heads around the axle to make sure we don't need to change
text elsewhere, or to define which withs are really withs.  (It might be
nice to do away with the current grammar restriction that requires a
context clause to begin with "with", or pragmas followed by "with", but
that is a detail.)

Oh, one final note.  I see no problem with:

with A; use type in A.B;

I think that the methodological rule should be followed that to use a
type from a child package, the parent has to be named earlier in a with
in the context clause.  This might end up in some cases requiring
something like:

with A; use type in A.B;
package A.C is...

I can accept that.  However, notice that:

with A; use type in A.B;
package A is....

should and would be illegal.

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

From: Randy Brukardt
Sent: Wednesday, January 22, 2003 7:43 PM

I want to give a more realistic example than in the AIs, so that we can see
how it will work with the various solutions proposed. So, I'm going to
describe how I would use alternative #5 (and #4, for that matter) in the
Claw Builder. This example shows (I think) why I think that non-transitivity
is a non-starter.

The Claw Builder is a real, existing program which could use this facility.
The problem is that some objects need references to other types of objects,
and these needs are circular. For instance, (some) types of window objects
include menu objects. And some types of menu objects include actions that
open a window.

The current Claw Builder solves this problem by using names rather than
access objects to connect the objects in some cases. This is usually done
only where necessary to break circularities. For instance, menu objects name
the windows they are to open, rather than linking to them. Using names
causes several problems:
   -- Accesses to the linked object is much slower, as they have to be
looked up by name before use;
   -- If the user renames the linked object, we have to walk the entire
project to insure any names are updated;
   -- If the user copies the linked object and then renames the copy (the
required behavior), we have to be careful NOT to walk the project and update
names -- harming code reuse.
   -- We can't have overloaded names (not a problem for windows, but can
happen in other cases).

A root window object is an abstract object with a fairly large set of
operations. Each concrete object has to provide implementations for many of
these operations (some it can inherit). All of these operations are
dispatching. Typically, a user of the operation would apply it to a list of
windows using an iterator generic, with the operation dispatching to the
correct implementation. For the purposes of this discussion, we'll look at
just a few: Show, Hide, Display_Name.

The existing package looks something like:

   package CBuild_Root is
      type Root_Window_Type is abstract new
	    Ada.Finalization.Limited_Controlled with private;
      type Any_Window_Access_Type is access all Root_Window_Type'Class;

      procedure Show (Window : in out Root_Window_Type) is abstract;
      procedure Hide (Window : in out Root_Window_Type) is abstract;
      function Display_Name (Window : in Root_Window_Type) return String is abstract;
      ...
   end CBuild_Root;

Now, I would construct an abstract of this package for use in circular
definitions. (Caveat, I haven't actually done this, not having a compiler
with this feature.) Using the syntax of alternative #5, this would look
like:

   abstract of CBuild_Root_Definition;
   package CBuild_Root is
      type Root_Window_Type is tagged separate in CBuild_Root_Definition;
      type Any_Window_Access_Type is access all Root_Window_Type'Class;

      procedure Show (Window : in out Root_Window_Type'Class);
      procedure Hide (Window : in out Root_Window_Type'Class);
      function Display_Name (Window : in Root_Window_Type'Class) return
String;
      ...
   end CBuild_Root;

This abstract actually can be used anywhere that you need a
Root_Window_Type, except when you need to construct an object of
Root_Window_Type, and when you need to create a new concrete object. (It
turns out that these are the same places in the Claw Builder, but that may
not be true generally.) All other uses would use the abstract and not the
"real" package. That's why I named it with the name of the current "root"
package.

In order to keep the access types compatible, the real package would be
modified to:

   with CBuild_Root;
   package CBuild_Root_Definition is
      type Root_Window_Type is abstract new
	    Ada.Finalization.Limited_Controlled with private;
      subtype Any_Window_Access_Type is CBuild_Root.Any_Window_Access_Type;

      procedure Show (Window : in out Root_Window_Type) is abstract;
      procedure Hide (Window : in out Root_Window_Type) is abstract;
      function Display_Name (Window : in Root_Window_Type)
           return String is abstract;
      ...
   end CBuild_Root_Definition;

The body of CBuild_Root would need visibility on the real type so that it
could implement the procedures:

   with CBuild_Root_Definition;
   package body CBuild_Root is
      procedure Show (Window : in out Root_Window_Type'Class) is
      begin
          CBuild_Root_Definition.Show (Window);
      end Show;
      procedure Hide (Window : in out Root_Window_Type'Class) is
      begin
          CBuild_Root_Definition.Hide (Window);
      end Hide;
      function Display_Name (Window : in Root_Window_Type'Class) return String is
      begin
          return CBuild_Root_Definition.Display_Name (Window);
      end Display_Name;
      ...
   end CBuild_Root;

Now, essentially any use of an Any_Window_Access_Type pointer could be
implemented without withing the "abstracted package" at all. Only the
packages define the concrete window objects would with
CBuild_Root_Definition at all.

For instance, in the menu case, we would have something like (this is
greatly simplified):
  with CBuild_Root;
  package CBuild_Menu is
    type Menu_Item is record
       Name : String (1..20);
       Action : Action_Type;
       Dialog : CBuild_Root.Any_Window_Access_Type; -- If Action=Open_Dialog.
    end record;
    procedure Simulate_Action (Item : in Menu_Item);
  end CBuild_Menu;

  with CBuild_Root;
  package body CBuild_Menu is
    procedure Simulate_Action (Item : in Menu_Item) is
    begin
       if Item.Action = No_Action then
           null;
       elsif Item.Action = Open_Dialog then
           CBuild_Root.Show (Item.Dialog.all);
       ... -- Other actions.
       end if;
    end Simulate_Action;
  end CBuild_Menu;

The dereference in Show is allowed, because (in implementation terms) we
don't need to know anything at all about the real type in order to generate
the call. Such a call cannot be dispatching (the only way to see a primitive
operation is for the completion to be "available"). Thus, it cannot be using
a tag. And we know the parameter passing mode (by reference), and we know
that the body (or at least some body) must be in the scope of the
completion, or nothing at all must be done with the type. I believe Tucker's
rules in Alternatives #4 and #5 do allow this dereference.

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

From: Tucker Taft
Sent: Wednesday, January 22, 2003 7:54 AM

Here is yet another approach to the circular dependence
problem.  It has the following nice characteristics:

   1) No new kinds of compilation units
   2) No new kinds of context clauses
   3) No new kinds of type definitions
   4) Minimal syntax inventiveness

It was inspired by trying to deal with Dan's ideas, Randy's
ideas, and the original package "abstract" idea.

Now that I have you all breathless with anticipation...

package P is
    ...

    child package C is
        type T;
        type T_Ptr is access T;
    end C;
    ...
end P;

The basic idea is that you can give a little "taste" (or "prefix") of
a child package in the parent package spec.  Anyone who
"with"s the parent sees the "prefix" of the child.  If they
"with" the child explicitly, then they see the whole
spec of the child package.

This is analagous to the notion of a package subunit, except
that it is in the spec rather than the body, and you
reveal part of the spec of the child.

Any sort of declaration may appear in such a child package
prefix.  The full visible part of the child package is
simply the concatenation of the prefix and the part that is
compiled separately.

Since we know that any unit that "with"s a child implicitly
"with"s its parent, there will never be a situation where
a unit will see the "full" child but not see the prefix.

Pretty cool, eh?

Fire away...

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

From: Robert Dewar
Sent: Wednesday, January 22, 2003 8:16 AM

I like this at first glance, but one query, why not just say

   package P.C is

instead of introducing the keyword child. The reason I don't like this
particular choice of keywords is that it is odd to have child units as
a first class feature of the language, and child as a keyword, and yet
(in the normal case) child units do not use the keyword child. (Also
child would be a pretty deadly keyword to add, since it is a VERY
common identifier in any program dealing with trees etc).

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

From: Robert A. Duff
Sent: Wednesday, January 22, 2003 10:09 AM

Tuck says:

> > Pretty cool, eh?

Yes.

Robert says:

> I like this at first glance, but one query, why not just say
>
>    package P.C is
>
> instead of introducing the keyword child.

I think I like Robert's suggested syntax.

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

From: Jean-Pierre Rosen
Sent: Wednesday, January 22, 2003 10:39 AM

If I understand correctly, this is the old package abstract stuff, with the
additional constraint that the abstract must be for a child, and declared
within the parent.

Why not then:
    package abstract P.C is ....

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

From: Robert I. Eachus
Sent: Wednesday, January 22, 2003  1:22 PM

The idea looks good, but it will need a lot of work.  The key to the
proposal is that incomplete types can appear in the abstract (or
whatever it is called) of the child, and completion deferred until the
spec of the child is compiled.  As for any other "goodies,"  I am
strongly in favor of a minimalist approach.  I think that allowing
access and discrete types as well is harmless enough and
methodologically sound, but beyond that I hesitate to go.  (The access
types could be declared in the parent, but I don't like that on
methodological grounds, and enumeration types and  other discrete types
may be needed for discriminants.)  Incidentally if complete types are
permitted, they should be required to be repeated in the actual child
package spec, but the end of the abstract should be a freezing point.

I can probably be convinced that there is a need for constants--I am not
convinced, but I can be.  However, subprograms, task types, protected
types, and variables all seem to open unnecessary cans of worms.

Oh, and I will offer one other syntax proposal:

              separate package B is {...} end B;

We could even allow:

              separate package A;

As a way of specifying that a child of that name must be part of the
partition, but nothing else.

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

From: Tucker Taft
Sent: Wednesday, January 22, 2003  2:45 PM

Yes, this proposal is very similar to the "package abstract"
or "package P'Interface" ideas.
I chose the "child" keyword just to avoid any
tricky keyword convolutions or reinterpretations.  I don't care
too much what we use.  As JP says, the important
thing is to put the interface/prefix/abstract/"taste"
into the parent spec.  This seems to solve a whole bunch of problems.
Presumably a private child's prefix would have to go
into the private part of the parent spec.

As far as syntax, we might have:

     - child package C is ... end C;
     - package P.C is ... end P.C;
     - package abstract P.C is ... end P.C;
     - package abstract C is ... end C;(for completness)
     - separate package C is ... end C;
     - package C is separate ... end C;

I find it odd to declare something *textually* inside P
with the name "P.C".  There is no precedent for that.
So I would prefer the ones that just talk about "C".
The ones with the word "separate" seem nicely suggestive
of body stubs, which are certainly pretty close to this.
Note that body stubs don't use the "P.C" style name for
the stub.

Although we have talked about "package abstracts"
this really isn't an "abstract" in the sense of a summary.
It is more of a "prefix" in that I am presuming declarations
are *not* repeated in the "full" visible part (there seems
no reason to repeat them, and dealing with conformance of a
sequence of declarations makes my hair stand on end ;-).

Putting the word "separate" after the "is" is
more consistent with stubs, and the only change is that
rather than an immediate ";" you may follow it with
one or more declarations and an "end [id];".  And of
course, the keyword "body" is omitted.

I don't think I agree with Robert Eachus' desire to restrict
the kind of declarations that could go in the prefix, but
I do agree that anything that is not an incomplete type
declaration will be frozen at the end of the enclosing library
unit spec, in the same way things in a nested package spec are frozen
when reaching the end of the enclosing library unit spec.

So no giving some but not all of the dispatching operations,
or no deferring the rep-clause for a (non-incomplete) type to the
full visible part.

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

From: Dan Eilers
Sent: Wednesday, January 22, 2003  7:43 PM

> Yes, this proposal is very similar to the "package abstract"
> or "package P'Interface" ideas.

I believe Randy and my recent proposals have the full type in
the parent and the type stub in the child, which is backwards
from this idea.  It seems more intuitive to me to have the full
type in the parent, since that is what would normally be with'd,
but maybe its not a big deal.


> Presumably a private child's prefix would have to go
> into the private part of the parent spec.

If you have a such a package prefix in a private part, do you
propose that the corresponding child package could contain the
completion of a declaration in the visible part?  If so, that
might solve the need for separately compiled private parts.

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

From: Randy Brukardt
Sent: Wednesday, January 22, 2003 9:04 PM

On first glance this proposal doesn't look too bad, but I have some
concerns.

> Here is yet another approach to the circular dependence
> problem.  It has the following nice characteristics:
>
>   1) No new kinds of compilation units
>   2) No new kinds of context clauses
>   3) No new kinds of type definitions
>   4) Minimal syntax inventiveness

This reminded me of Wirth's Turing Award lecture. In it, (talking about
PL/1), he said the initial descriptions of features were "promises of
unalloyed delight", but that as the work went on, the descriptions got
messier and messier... (I hope I haven't misquoted Prof. Wirth.)

Anyway, one minor nit is that (3) isn't true. Every proposal we've worked on
leans heavily on tagged incomplete types. Indeed, I can come close to solve
these problems with those alone (and not other feature at all). Without
them, you can't do enough with the incomplete types to make any of these
ideas worthwhile. (And we sure as heck don't want to allow 'Class on things
that might not turn out to be tagged.)

And of course (1) is a fudge here. You are adding a new kind of program
unit, and you've just chose to hide it inside a "normal" compilation unit.
Which leads to one concern: usually these things are used at the root of
type trees, because it is usually the intersection of different object
classes where circularity problems come up. This idea means that you have to
introduce a dummy parent package just to hold this child. For instance, for
my CBuild example:

   package CBuild_Windows is
      package Root is separate -- I really want to type an 'is' here...
          type Root_Window_Type is tagged;
          type Any_Window_Access_Type is access all Root_Window_Type'Class;
          procedure Show (Window : in out Root_Window_Type'Class);
          procedure Hide (Window : in out Root_Window_Type'Class);
          function Display_Name (Window : in Root_Window_Type'Class)
              return String;
      end Root;
   end CBuild_Windows;

More annoying is that you can't even rename this away at the library level
(as the rename would clearly refer to the full package, not just this stub).
You'd have to rename in every package that it is used in. Since I would plan
to use this in as many places as possible, that is annoying.

This also seems to be a pit of visibility issues. We would have a new
concept of this additional "part" messing up visibility. Clearly, we'd have
to check for and disallow homographs in the real spec. But we'd also have to
change the names of the "real" operations, because otherwise all of the
calls would be ambiguous.

   package CBuild_Windows.Root is
       type Root_Window_Type is limited tagged with private; -- Completion
       procedure Real_Show (Window : in out Root_Window_Type);
       procedure Real_Hide (Window : in out Root_Window_Type);
       function Real_Display_Name (Window : in Root_Window_Type)
           return String;
   end CBuild_Windows.Root;

We can't call the real operation "Show" here, because that would make it
impossible to call Show anywhere is this 'with'ed. (Well, at least without a
full qualification on the argument, which leaves a lot to be desired). At
least with Alternatives #4 & #5, you can use the package name to separate
them, or "use" just one of the packages. Indeed, it would be rare that you'd
with both anyway.

I presume that you are restricting these "package spec. stubs" (for the lack
of a better name) to library level package specifications? The rules for
nested ones make my head hurt.

I wonder what the rules for use of the incomplete type ought to be? If you
can't write (as in my example):

  with CBuild_Window;
  package CBuild_Menu is
    type Menu_Item is record
       Name : String (1..20);
       Action : Action_Type;
       Dialog : CBuild_Window.Root.Any_Window_Access_Type;
              -- If Action=Open_Dialog.
    end record;
    procedure Simulate_Action (Item : in Menu_Item);
  end CBuild_Menu;

  with CBuild_Window;
  package body CBuild_Menu is
    procedure Simulate_Action (Item : in Menu_Item) is
    begin
       if Item.Action = No_Action then
           null;
       elsif Item.Action = Open_Dialog then
           CBuild_Window.Root.Show (Item.Dialog.all);
       ... -- Other actions.
       end if;
    end Simulate_Action;
  end CBuild_Menu;

then we've lost quite a bit of expressive power that we have with
Alternatives #4 & 5. OTOH, there might be an opportunity to simplify the
existing rules some. So I'd like to know what they'd be.

Elaboration is a disaster, but that's true for any solution to this problem.
(You really have little choice but to elaborate all of the specs first, then
all of the bodies.)

Still, it's the visibility rules that worry me the most. I fear that it will
take two years to figure them out; we won't have a clue about them two weeks
from now at Padua. I know I can't do it in time for the meeting, I have a
lot of other AIs that need to be done. The notion of having different
visibility to different parts of the spec. is scary, and this seems like a
big, big job in the symbol table of a compiler (even if it isn't a big job
conceptually).

So we need a proposal with the visibility details worked out before I could
even imagine to decide if it really is simpler, rather than just appearing
that way without the details worked out.

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

From: Tucker Taft
Sent: Wednesday, January 22, 2003 10:03 PM

> Anyway, one minor nit is that (3) isn't true. Every proposal we've worked on
> leans heavily on tagged incomplete types. Indeed, I can come close to solve
> these problems with those alone (and not other feature at all). Without
> them, you can't do enough with the incomplete types to make any of these
> ideas worthwhile. (And we sure as heck don't want to allow 'Class on things
> that might not turn out to be tagged.)

True, we should add the tagged incomplete types.

> And of course (1) is a fudge here. You are adding a new kind of program
> unit, and you've just chose to hide it inside a "normal" compilation unit.

Well we were told that having a new kind of compilation unit
was a much bigger deal, since the program library support
is scattered across more tools than just the compiler.
Similarly, new kinds of context clauses and new kinds of
interdependencies between units also seems to cause changes
in non-compiler tools.  So an important feature of this
proposal is that the changes are only *within* compilation
units.

> Which leads to one concern: usually these things are used at the root of
> type trees, because it is usually the intersection of different object
> classes where circularity problems come up. This idea means that you have to
> introduce a dummy parent package just to hold this child.

I don't feel too worried about this, since a lot of
subsystems seem to have a root package that is almost
empty (e.g. Ada.Numerics, and this forms a natural place
to host these prefix packages.

> ... For instance, for
> my CBuild example:
>
>    package CBuild_Windows is

Why wouldn't this be package (subsystem) named "Cbuild"
and then child named Windows?

>       package Root is separate -- I really want to type an 'is' here...
>           type Root_Window_Type is tagged;
>           type Any_Window_Access_Type is access all Root_Window_Type'Class;
>           procedure Show (Window : in out Root_Window_Type'Class);
>           procedure Hide (Window : in out Root_Window_Type'Class);
>           function Display_Name (Window : in Root_Window_Type'Class)
>               return String;
>       end Root;
>    end CBuild_Windows;
>
> More annoying is that you can't even rename this away at the library level
> (as the rename would clearly refer to the full package, not just this stub).
> You'd have to rename in every package that it is used in. Since I would plan
> to use this in as many places as possible, that is annoying.

I've lost you on the rename issue.  Just because a child package has
a prefix, there should be no reason you couldn't rename it.

> This also seems to be a pit of visibility issues. We would have a new
> concept of this additional "part" messing up visibility. Clearly, we'd have
> to check for and disallow homographs in the real spec. But we'd also have to
> change the names of the "real" operations, because otherwise all of the
> calls would be ambiguous.

Again, I have lost you.  Why are you putting any operations
in the package prefix?  And what makes these operations
more or less real than operations in the full package?

I don't see any visibility issues, so we are clearly thinking
about this differently.  There seems no particular reason to
put anything in a package prefix other than a few type declarations.
Operations seem redundant (though I don't see any technical reason
to disallow them).

>    package CBuild_Windows.Root is
>        type Root_Window_Type is limited tagged with private; -- Completion
>        procedure Real_Show (Window : in out Root_Window_Type);
>        procedure Real_Hide (Window : in out Root_Window_Type);
>        function Real_Display_Name (Window : in Root_Window_Type)
>            return String;
>    end CBuild_Windows.Root;
>
> We can't call the real operation "Show" here, because that would make it
> impossible to call Show anywhere is this 'with'ed.

Again, I have lost you why you declared various class-wide
operations in the package prefix.  The "with" type and
the type stub didn't allow any operations to be declared,
so I don't understand why you need them with this proposal.

> (Well, at least without a
> full qualification on the argument, which leaves a lot to be desired). At
> least with Alternatives #4 & #5, you can use the package name to separate
> them, or "use" just one of the packages. Indeed, it would be rare that you'd
> with both anyway.

I have completely lost you now.

> I presume that you are restricting these "package spec. stubs" (for the lack
> of a better name) to library level package specifications? The rules for
> nested ones make my head hurt.

I don't see any need for nested prefixes, though I
don't see any particular difficulty here.

My model is that these would be handled pretty much
the same way specs and bodies are handled.  That is,
when you get to the full package spec, you reenter
the scope you were in when you processed the prefix,
and keep adding more declarations.  From the "outside"
if you only "with" the parent, then you only see the
declarations in the prefix.  If you "with" the child,
then you see the declarations in both the prefix and
the full spec for the child.  I don't understand where
the visibility complexity comes in.  There are a number
of places already in Ada where different places see
more or fewer declarations within a package.  E.g.,
when in a private child, you see both the visible
and private part.  When in a stub, you see all declarations
that precede the stub.

Can you give me a simple example of the visibility
issues you perceive?  I am getting mixed up by your
relatively complicated example, and your apparent
desire to declare class-wide operations in the
package prefix.

> I wonder what the rules for use of the incomplete type ought to be? If you
> can't write (as in my example):
>
>   with CBuild_Window;
>   package CBuild_Menu is
>     type Menu_Item is record
>        Name : String (1..20);
>        Action : Action_Type;
>        Dialog : CBuild_Window.Root.Any_Window_Access_Type;
>               -- If Action=Open_Dialog.
>     end record;
>     procedure Simulate_Action (Item : in Menu_Item);
>   end CBuild_Menu;
>
>   with CBuild_Window;
>   package body CBuild_Menu is
>     procedure Simulate_Action (Item : in Menu_Item) is
>     begin
>        if Item.Action = No_Action then
>            null;
>        elsif Item.Action = Open_Dialog then
>            CBuild_Window.Root.Show (Item.Dialog.all);
>        ... -- Other actions.
>        end if;
>     end Simulate_Action;
>   end CBuild_Menu;
>
> then we've lost quite a bit of expressive power that we have with
> Alternatives #4 & 5. OTOH, there might be an opportunity to simplify the
> existing rules some. So I'd like to know what they'd be.

I need more help understanding the power you are talking about.
Can you be more explicit?  I am lost in the details of
this example.

> Elaboration is a disaster, but that's true for any solution to this problem.
> (You really have little choice but to elaborate all of the specs first, then
> all of the bodies.)

I don't understand why elaboration is affected at all.
whether a declaration is in a nested package or in
the enclosing package is irrelevant for elaboration.
The elaboration happens in the order of the declarations
within a single package-ish compilation unit.  I don't
see this changing even if a package prefix happens to
be nested inside the compilation unit.

Clearly the parent spec compilation unit has to be
elaborated before any child compilation units, but
the child compilation units don't need to have all their
specs elaborated before any bodies.  One of the
main advantages of this proposal as I see it is there
would be *no* change to compilation-unit-level processing,
such as compilation unit elaboration order determination.

> Still, it's the visibility rules that worry me the most.

I claim they are intuitively obvious!  Obviously we must
not have the same understanding of how this proposal would
work.

> I fear that it will
> take two years to figure them out; we won't have a clue about them two weeks
> from now at Padua. I know I can't do it in time for the meeting, I have a
> lot of other AIs that need to be done. The notion of having different
> visibility to different parts of the spec. is scary, and this seems like a
> big, big job in the symbol table of a compiler (even if it isn't a big job
> conceptually).

Well I don't know anything about your compiler, of course,
but in ours, each declarative region has a sequence of declarations,
each declaration having its own "logical position."  All lookups within a
region need to take a logical position "cutoff" which is
the last declaration that is visible from where the lookup is
taking place.  This deals with private part visibility,
visibility at the point of a stub, etc.  Clearly if you
only "with" the parent spec, then the last declaration visible
in the child package region is the end of its prefix.

> So we need a proposal with the visibility details worked out before I could
> even imagine to decide if it really is simpler, rather than just appearing
> that way without the details worked out.

I will be happy to do that, but I would appreciate some
better understanding of the problems you perceive,
because I fear I will not address these problems otherwise.

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

From: Tucker Taft
Sent: Wednesday, January 22, 2003 10:10 PM

Dan Eilers wrote:
>>Yes, this proposal is very similar to the "package abstract"
>>or "package P'Interface" ideas.
>
> I believe Randy and my recent proposals have the full type in
> the parent and the type stub in the child, which is backwards
> from this idea.  It seems more intuitive to me to have the full
> type in the parent, since that is what would normally be with'd,
> but maybe its not a big deal.

I seems important that some compilation
units only see the incomplete type, while others see both
the incomplete type and its completion.  The existing
rules for child packages is that if you see a child unit,
then you always see its parent.  Changing that seems
pretty disruptive.  Presuming you don't change that, then clearly
the incomplete type needs to be in the parent unit, while the
completion needs to be in the child unit.

>>Presumably a private child's prefix would have to go
>>into the private part of the parent spec.
>
> If you have a such a package prefix in a private part, do you
> propose that the corresponding child package could contain the
> completion of a declaration in the visible part?  If so, that
> might solve the need for separately compiled private parts.

My hope is that the rules would be changed as little
as possible, meaning that if an incomplete type is
declared in the prefix of the visible part of the child,
the it has to be completed somewhere later in the
visible part, either in the prefix itself, or in the
visible part of the "full" spec.  This wouldn't
depend on whether the child was private or public.

What I was impllying was that if the child is public, then
its prefix (if any) must be in the visible part of its parent,
and if a child is private, then its prefix (if any) must be
in the private part of its parent.

I do agree that this proposal might reduce the need for separately
compiled private parts, though I haven't really pursued that
investigation.  I am mostly trying to come up with a simple
solution to the circularly dependent package problem

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

From: Pascal Leroy
Sent: Thursday, January 23, 2003  3:48 AM

> package P is
>     ...
>     child package C is
>         type T;
>         type T_Ptr is access T;
>     end C;
>     ...
> end P;

I hate the notion that the type structure is tied to the package structure, as
it makes changes extremely painful during maintenance.

Assume that you have two root library packages P1 and P2 declaring types T1 and
T2.  Assume moreover that T1 depends on T2.  For instance:

    with P2;
    package P1 is
        type T1 is
            record
                C : P2.T2;
            end record;
    end P1;

    package P2 is
        type T2 is ... ;
    end;

At this point, in a real project, you probably have a lot of code that
references names in P1, including P1.T1.

Say that, during maintenance, you have to introduce a circularity, and T2 must
now contain a pointer to T1.  You would presumably do this by adding a "prefix"
and pushing down the full type declaration for T1 in a child unit:

    package P1_Root is
        child package P1 is
            type T1;
            type AT1 is access T1;
        end P1;
    end P1_Root;

    with P2;
    package P1_Root.P1 is
        type T1 is
            record
                C : P2.T2;
            end record;
    end P1_Root.P1;

    with P1_Root;
    package P2 is
        type T2 is
            record
                C : P1_Root.P1.T1;
            end record;
    end P2;

Now this means that most of the references to P1 must change to reference
P1_Root.P1.  This includes the places that declare objects of type T1 or
otherwise need to view the full type declaration for T1, as well as places that
need to reference operations on T1.  True, you can alleviate this somewhat by
providing library-level renamings or skins, but that's still a lot of work for a
rather mundane change.  When I do that in C++ all I have to do is type the 5
letters c, l, a, s, s.  When I do that in Ada I would have to stand on my head?
Come on!

Note that none of the other proposals have that drawback, as they don't require
that you change the place where the full type (and its operations) are declared.

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

From: Robert A. Duff
Sent: Thursday, January 23, 2003  7:44 AM

If people keep coming up with good ideas for solving the circular
dependence problem, it will never get solved.

Half :-).

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

From: Robert I. Eachus
Sent: Thursday, January 23, 2003  12:33 PM

Pascal Leroy wrote:

>I hate the notion that the type structure is tied to the package structure, as
>it makes changes extremely painful during maintenance.
>
>Assume that you have two root library packages P1 and P2 declaring types T1 and
>T2.  Assume moreover that T1 depends on T2...

From one point of view, this is a valid issue, from another it is
nonsense.  I have always taught that during the design phase of an Ada
project, you don't model the solution, you model the problem space.  To
use the example of a directory system, any solution that makes people
subordinate to offices, or offices subordinate to people is wrong.   The
problem space has offices associated with zero or more people, and
people associated with zero or more offices.  Any program structure that
doesn't reflect this is going to be subject to major restructuring
during development and maintenance.  (Of course, don't take this to
extremes.  Current cosmological theories not only permit time travel,
they require that causality not hold in all circumstances.  But I
wouldn't chide a programmer for not allowing negative delays between
cause and effect. ;-)

    package Root is
      child package P1 is
        type T1;
        type AT1 is access T1;
      end P1;
      child package P2 is
        type T2;
        type AT2 is access T2;
      end P2;
    end Root;

    package Root.P1 is
      type T1 is record
        C : P2.T2;
      end record;
      ...
    end Root.P1;

    package Root.P2 is
      type T2 is record
        C : P1.T1;
      end record;
      ...
    end Root.P2;

Even if the initial version of the program doesn't need component C of type T2,
this structure is clean, easy, and reflects the fact that T1 and T2 are of
equal precedence.  You might object to a Root package for a system like this,
but on methodological grounds, again I will disagree.  Whenever you have a
situation where several packages must be included in or excluded from a
partition as a whole, good design requires that the subsystem be identified as
such.

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

From: Tucker Taft
Sent: Thursday, January 23, 2003  1:59 PM

I guess I am surprised that large systems
don't use a package hierarchy already,
with nearly empty "root" packages.
But obviously Ada 83 legacy code doesn't do that,
but then of course Ada 83 legacy code doesn't have
circular dependences ;-).

Note that it is relatively painless to introduce a layer
at the "top" of a hierarchy, and make everything into
a child package.  The only changes are the "with" clauses,
everything else stays the same, since the top-level name
is implicit everywhere.  It would be essentially as
though package Standard were now spelled "Standard.Top".

I also wonder how common it will be to consider introducing a circular
dependence a typical "maintenance" activity.  Circular type dependence almost
always implies some kind of recursive processing as well, so this doesn't seem
like a "small" change.

I agree it would be great if we could have stand-alone package prefixes, but
the impact of that just seemed very large last time we visited it.  Perhaps we
could design a syntax for stand-alone prefixes, but focus on getting the nested
ones approved, and then work on determining the implementation impact of having
stand-alone ones.  I really think the nested ones are relatively simple to
implement, whereas the stand-alone ones imply a new kind of compilation unit, a
new kind of "with" clause, new library-item elaboration-order issues, and
generally a lot more effort and complexity.

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

From: Robert A. Duff
Sent: Thursday, January 23, 2003  1:59 PM

> I guess I am surprised that large systems
> don't use a package hierarchy already,
> with nearly empty "root" packages.

Certainly all the large programs I write have a small number of root
packages, and everything else is under those.

So are you saying that typically the types in question will already be
in some child package P.C, so to make P.C.T mutually recursive with
something else, all you have to do is add some code to P, without
changing clients of P.C?  If so, that seems to address Pascal's
concern.

> But obviously Ada 83 legacy code doesn't do that,
> but then of course Ada 83 legacy code doesn't have
> circular dependences ;-).

But it wishes it did.  ;-)

> Note that it is relatively painless to introduce a layer
> at the "top" of a hierarchy, and make everything into
> a child package.  The only changes are the "with" clauses,
> everything else stays the same, since the top-level name
> is implicit everywhere.  It would be essentially as
> though package Standard were now spelled "Standard.Top".
>
> I also wonder how common it will be to consider introducing a circular dependence
> a typical "maintenance" activity.  Circular type dependence almost always
> implies some kind of recursive processing as well, so this doesn't seem
> like a "small" change.

That's a good point.  Generally, it seems like mutually recursive types
have to be designed "together" in some sense.

Anyway, I would gladly do a lot of work on my code, if there were *any*
reasonable solution to this problem.

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

From: Dan Eilers
Sent: Thursday, January 23, 2003  2:44 PM

Randy wrote:
>  Without [tagged incomplete types] you can't do enough with the
>  incomplete types to make any of these ideas worthwhile.

Is it really the case that we're only solving the circular
dependence problem for tagged types?  There are plenty of
examples of inherently circular problem domains that are
reasonably modeled using untagged types, such as an Ada parser
where the abstract syntax tree nodes are represented using
variant records.


In Tucker's latest proposal:

> package P is
>     ...
>
>     child package C is
>         type T;
>         type T_Ptr is access T;
>     end C;
>     ...
> end P;

This seems a step backwards from the type stub proposal.
It isn't much different from

  package P is
      ...

      Type T is separate in P.C;
      Type T_ptr is access T;
      ...
  end P;

Both proposals allow the full type in a child package.
Neither proposal has a context clause to alert the
reader to the reference to a child package.

Tucker's proposal is more verbose.  It also seems
preferable (as it looks like Pascal noted) to have the
incomplete type declared immediately within P (as in
the type stub proposal), rather than nested in the
prefix package C.

The type stub proposal is more flexible, in that it
allows the full type to be in any designated package.
If this flexibility really isn't needed, then the
type stub proposal could be similarly restricted.
With such a restriction, there might be much less
user demand for a context clause, and we might be done.


Tucker wrote:
> The existing
> rules for child packages is that if you see a child unit,
> then you always see its parent.  Changing that seems
> pretty disruptive.  Presuming you don't change that, then clearly
> the incomplete type needs to be in the parent unit, while the
> completion needs to be in the child unit.

Well, you have to disrupt something to break the circularity.
You either provide a way to disrupt the existing rule that
a child unit implies a semantic dependency on its parent,
or you disrupt the exiting rule that the parent's spec can't
refer to its own unborn child.  It seems like a close call
as to which is the bigger disruption.  Usability would argue
that most references be to the parent package.


> I do agree that this proposal might reduce the need for separately
> compiled private parts, though I haven't really pursued that
> investigation.  I am mostly trying to come up with a simple
> solution to the circularly dependent package problem

Yes, first things first.  But we do have several very closely
related problems to solve, and it would be nice if the solutions
are harmonious.  If you have a way of deferring the completion
of a public incomplete type to a separately compiled child unit,
with no semantic dependency on the child unit, then it isn't a
very big step to defer the completion of a private type to a
separately compiled child unit with no semantic dependency.

Similarly, you could also defer the completion of a deferred
constant to a separately compiled child unit with no semantic
dependency (an issue you raised before but which I believe got
lost).

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

From: Randy Brukardt
Sent: Thursday, January 23, 2003  5:23 PM

Tucker said (replying to me):

>Can you give me a simple example of the visibility
>issues you perceive?  I am getting mixed up by your
>relatively complicated example, and your apparent
>desire to declare class-wide operations in the
>package prefix.

The point of my example was to look at how this would be used in practice,
and not in the vacuum of a blank piece of a paper of a hypothetical system.

Tucker said later:
> I also wonder how common it will be to consider introducing a circular
> dependence a typical "maintenance" activity.  Circular type dependence almost
> always implies some kind of recursive processing as well, so this doesn't seem
> like a "small" change.

Hogwash!

I have an existing application with circular dependencies. It uses various
hacks to deal with that in Ada 95. The application has bugs, directly caused
by those hacks. (I outlined all of this when I gave the example.) I could
build a hack on top of a hack to fix the bugs, or I could use this spiffy
new feature to make the circular dependence real, and then those bugs are
gone for good.

I doubt that this is all that unusual of a situation; Ada programmers have
been working around problems of circularity since 1980.

Tucker said (replying to me):

>> More annoying is that you can't even rename this away at the library level
>> (as the rename would clearly refer to the full package, not just this stub).
>> You'd have to rename in every package that it is used in. Since I would plan
>> to use this in as many places as possible, that is annoying.

>I've lost you on the rename issue.  Just because a child package has
>a prefix, there should be no reason you couldn't rename it.

This is a maintenance issue. If you have to introduce a dummy parent package
to make this work, then you would like to rename the stub for uses of it
alone, and rename the child for uses of it. You can certainly rename the
child at the library level:
   with CBuild_Windows.Root;
   package CBuild_Root renames CBuild_Windows.Root;
but you still have a semantic dependence on this unit. There is no way to
get a simple name for the stub alone at the library level.

You can rename it inside a scope, of course:
   with CBuild_Windows;
   package Whatever is
       package CBuild_Root is CBuild_Windows.Root;
       ...
   end Whatever;

But that distributes the change throughout the code.

Pascal explained why this is bad better than I can when he said:

> Now this means that most of the references to P1 must change to reference
> P1_Root.P1.  This includes the places that declare objects of type T1 or
> otherwise need to view the full type declaration for T1, as well as places that
> need to reference operations on T1.  True, you can alleviate this somewhat by
> providing library-level renamings or skins, but that's still a lot of work for a
> rather mundane change.  When I do that in C++ all I have to do is type the 5
> letters c, l, a, s, s.  When I do that in Ada I would have to stand on my head?
> Come on!

Tucker is surprised by this:
> I guess I am surprised that large systems don't use a package hierarchy already,
> with nearly empty "root" packages. But obviously Ada 83 legacy code doesn't do that,
> but then of course Ada 83 legacy code doesn't have circular dependencies ;-).

It doesn't have EXPLICIT circular dependencies, but I bet it has ones that
were hacked around.

In any case, I've only used a "root" package once, and that was with Claw.
In that case, the main issues were avoiding pollution of the user's
namespace, visibility into the private parts of types, and providing a place
so that all of the interrelated types could be declared (because we didn't
have a circularity solution). The primitive operations all had to be there
as well, so the spec is 3700 lines and the body 7100 lines. Hardly "nearly
empty".

In every other case, the entire application was the "subsystem". The Claw
Builder is not small; there is 4.5 Megabytes of source code. (I know that
there are much larger systems out there.) The parts are interrelated enough
that there is very little that could be independent, so there is no reason
for a "subsystem" structure.

I certainly can see why some systems would be built with empty top-level
packages, but I don't like the idea of forcing people to build things that
way. Especially when they are not that way already.

Bob echoed Tucker:

> Certainly all the large programs I write have a small number of root
> packages, and everything else is under those.
>
> So are you saying that typically the types in question will already be
> in some child package P.C, so to make P.C.T mutually recursive with
> something else, all you have to do is add some code to P, without
> changing clients of P.C?  If so, that seems to address Pascal's concern.

But on a another forum (in unrelated thread), Bob says:

> ... It also requires the client to
> "with" bits and pieces of the abstraction.  That's *sometimes* desirable
> anyway, but in many cases, you want the client to get the whole
> abstraction in one with_clause.  And you don't want to have extra names
> polluting the namespace (sometimes you end up needing a name for the
> child package, *and* names for some stuff inside it).

Which is precisely my (and Pascal's) point.

The idea of my original example was to get the package abstract to be a
complete replacement for the original, existing package for almost all uses.
Then we can use the original name, and make very few changes to the existing
program. (Reading in objects in projects would have to be changed a lot, but
that's not relevant here.) The only change is to the packages that actually
implement the concrete versions of window objects; no other changes are
required.

Tucker asked:

>>    package CBuild_Windows is

>Why wouldn't this be package (subsystem) named "Cbuild" and then child
named Windows?

The practical answer is that "Cbuild" is the name of the application, and
thus it is the name of the main subprogram.

But, even ignoring that, it wouldn't be quite right. The original package
was supposed to be called CBuild_Root_Window; I shortened it because the
code using it was getting unreadable:
   CBuild_Root_Window.Show (CBuild_Root_Window.Root_Window_Type'Class (My_Parent.all));
This was sort of OK, because Windows are a bit more equal than other objects
in the builder - you can imagine an application without a menu or a font,
but a GUI application without a window? But we've lost some explanation, so
I'd prefer to reintroduce the 'lost' Windows prefix. (As you pointed out
elsewhere, direct visibility would mean that you wouldn't need to give it
inside of the set of Windows.)

Dan asked of me:
>>  Without [tagged incomplete types] you can't do enough with the
>>  incomplete types to make any of these ideas worthwhile.

>Is it really the case that we're only solving the circular
>dependence problem for tagged types?  There are plenty of
>examples of inherently circular problem domains that are
>reasonably modeled using untagged types, such as an Ada parser
>where the abstract syntax tree nodes are represented using
>variant records.

The flippant answer is that all useful types are Controlled, so by
definition they are tagged. :-)

The serious answer is that you can use these for untagged types. But for
type stubs, the disruption to your program structure would be much worse.
For Tucker's package stubs, the disruption to your program structure is
going to massive no matter what.

Dan also noted:

> Both proposals allow the full type in a child package. Neither proposal
> has a context clause to alert the reader to the reference to a child
package.

This is true, but this is true of child packages in general. Tucker is
taking advantage of that fact to avoid the context clause. Somehow I doubt
that is what the users who complained at SigAda had in mind, but it's a
pretty standard practice. If customers complain about something, give them
something worse to replace it. :-)

This is getting long. In part 2, I'll finish up looking at Tucker's
questions about visibility.

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

From: Randy Brukardt
Sent: Thursday, January 23, 2003  6:29 PM

> > This also seems to be a pit of visibility issues. We would have a new
> > concept of this additional "part" messing up visibility. Clearly, we'd have
> > to check for and disallow homographs in the real spec. But we'd also have to
> > change the names of the "real" operations, because otherwise all of the
> > calls would be ambiguous.
>
> Again, I have lost you.  Why are you putting any operations
> in the package prefix?  And what makes these operations
> more or less real than operations in the full package?

I think my putting operations in the package specification stub was a
mistake. The purpose of doing that in the type stub case is so that uses of
the package did not need to change. Since there are two separate packages,
and I do not want to force users to have to "with" both of them, I put
class-wide versions of the operations in the abstract package, which would
of course dispatch to the "real" operations declared in the package.

But that doesn't seem to be necessary in the package specification stub
proposal. (I'm calling it that, because that's the syntax we're using.) What
I should have written is:

   package CBuild_Windows is
      package Root is separate -- I really want to type an 'is' here...
          type Root_Window_Type is tagged;
          type Any_Window_Access_Type is access all Root_Window_Type'Class;
      end Root;
   end CBuild_Windows;

   package CBuild_Windows.Root is
       type Root_Window_Type is limited tagged with private; -- Completion
       procedure Show (Window : in out Root_Window_Type);
       procedure Hide (Window : in out Root_Window_Type);
       function Display_Name (Window : in Root_Window_Type)
           return String;
   end CBuild_Windows.Root;

   with CBuild_Windows.Root;
   package CBuild_Root renames CBuild_Windows.Root; -- Compatibility renames.

Then the uses would look something like:

  with CBuild_Window;
  package CBuild_Menu is
    type Menu_Item is record
       Name : String (1..20);
       Action : Action_Type;
       Dialog : CBuild_Window.Root.Any_Window_Access_Type;
              -- If Action=Open_Dialog.
    end record;
    procedure Simulate_Action (Item : in Menu_Item);
  end CBuild_Menu;

  with CBuild_Root;
  package body CBuild_Menu is
    procedure Simulate_Action (Item : in Menu_Item) is
    begin
       if Item.Action = No_Action then
           null;
       elsif Item.Action = Open_Dialog then
           CBuild_Root.Show (Item.Dialog.all);
       ... -- Other actions.
       end if;
    end Simulate_Action;
  end CBuild_Menu;

which doesn't seem too bad. I don't like the bizarre case of "depending" on
CBuild_Windows.Root in the spec. of CBuild_Menu, but not withing it. (And I
suspect that the people who complain about the context clause being missing
for type stubs would feel the same with this proposal. But I'm beginning to
think that is pretty much inherent in this problem...) But it certainly
could be lived with.

> I don't see any visibility issues, so we are clearly thinking
> about this differently.  There seems no particular reason to
> put anything in a package prefix other than a few type declarations.
> Operations seem redundant (though I don't see any technical reason
> to disallow them).

Well, you later said that you would ban nesting of these, and that a visible
one would have to be completed by a visible child. That would be the two
worst cases. But...

> > Still, it's the visibility rules that worry me the most.
>
> I claim they are intuitively obvious!  Obviously we must
> not have the same understanding of how this proposal would
> work.
>
> > I fear that it will
> > take two years to figure them out; we won't have a clue about them two weeks
> > from now at Padua. I know I can't do it in time for the meeting, I have a
> > lot of other AIs that need to be done. The notion of having different
> > visibility to different parts of the spec. is scary, and this seems like a
> > big, big job in the symbol table of a compiler (even if it isn't a big job
> > conceptually).
>
> Well I don't know anything about your compiler, of course,
> but in ours, each declarative region has a sequence of declarations,
> each declaration having its own "logical position."  All lookups within a
> region need to take a logical position "cutoff" which is
> the last declaration that is visible from where the lookup is
> taking place.  This deals with private part visibility,
> visibility at the point of a stub, etc.  Clearly if you
> only "with" the parent spec, then the last declaration visible
> in the child package region is the end of its prefix.

That's not quite how its done in Janus/Ada, although the basic idea is
similar. There also is a visibility flag used to deal with things like
homographs in the same scope. My main concern was that grafting on private
visibility into parent parts was a huge mess, and bugs are still turning up
from time to time. I can't see how this could possibly be any simpler than
that.

In any case, the rules for scope and visibility are complicated, and I
really do not see how this fits in to those. The answer cannot be that there
is no impact, because there are many rules dealing with bodies and private
parts and the like, and this is very similar to adding another "part".

> > So we need a proposal with the visibility details worked out before I could
> > even imagine to decide if it really is simpler, rather than just appearing
> > that way without the details worked out.
>
> I will be happy to do that, but I would appreciate some
> better understanding of the problems you perceive,
> because I fear I will not address these problems otherwise.

I admit that there is a lot of FUD in my concerns here. It's just when
someone says "it's simple, trust me", my B*S* detector goes off. The pattern
with these AIs is that "it's simple" until someone finds the fatal flaw.
"Private with" was simple -- until we wrote the rules. "With type" was
simple, but proved to be full of holes. "Pragma Overridding" was simple
until someone realized we needed "Optional_Overriding" too, and now the
private overridding problem has killed it completely.

I know that there can be other things going on between the parts. That
usually gets us in trouble for other visibility issues, so it going to take
a lot of convincing to prove to me that that does not happen in this case.
Probably, I'll need to see a fully worked out proposal, including wording,
and for Steve B. and Pascal to have OKed it, before I'll believe.

All that said, one thing you have not emphasized (and you should) is that
this proposal doesn't seem to need the two pages of "availability" rules
that the type stub proposal does. I asked you about that and got no straight
answer (which gives me no confidence that you've thought about the rest of
it in enough depth). But, presuming that is true, that is a significant
advantage of this proposal. (The 'availability' rules would be very murky
area both for language lawyers and for implementors; if they were right,
users wouldn't notice them at all; but it's hard to tell if they're right.)

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

From: Robert Dewar
Sent: Thursday, January 23, 2003  11:19 PM

> I guess I am surprised that large systems
> don't use a package hierarchy already,
> with nearly empty "root" packages.

Seeing as many large Ada programs are derived from legacy Ada 83 systems,
you should not be so surprised. In fact I have seen very few of the large
systems we deal with structured this way.

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

From: Jean-Pierre Rosen
Sent: Friday, January 24, 2003  1:49 AM

> I agree it would be great if we could have stand-alone
> package prefixes, but the impact of that just seemed
> very large last time we visited it.  Perhaps we could design a syntax
> for stand-alone prefixes, but focus on getting the nested ones
> approved, and then work on determining the implementation impact
> of having stand-alone ones.  I really think the nested ones are
> relatively simple to implement, whereas the stand-alone ones imply
> a new kind of compilation unit, a new kind of "with" clause, new
> library-item elaboration-order issues, and generally a lot more effort and complexity.
>
Well... Thinking about it.
There is no circular dependency problem if all packages are nested within one
big package. The only new possibility of this solution is to separate (part of)
the specification. Separating the body was of course already possible.

The question is: will the people who were unhappy with the nested packages
solution be willing to accept this one?

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

From: Pascal Leroy
Sent: Friday, January 24, 2003  3:55 AM

Bob E. argued:

> project, you don't model the solution, you model the problem space.  To
> use the example of a directory system, any solution that makes people
> subordinate to offices, or offices subordinate to people is wrong.   The
> problem space has offices associated with zero or more people, and
> people associated with zero or more offices.  Any program structure that
> doesn't reflect this is going to be subject to major restructuring
> during development and maintenance.

I agree with you for the textbook example of offices and people.  However in
real life there are roughly a dozen layers of software between classes that
represent real-life entities like offices and people, and classes that
interface with software infrastructure like databases, UI, network or OS.
As you go down these layers, the decisions because harder and harder to make
and may have to change over time.

One common reason for change is performance: you may have to add a cache
somewhere, or to keep an extra pointer on the last accessed object, etc.
That can easily add circularities.

I ran into a situation like that in C++ a while ago, in the code of our Ada
editor.  I had two classes C1 and C2, and it was clear from day one that
they were dependent on each other.  C1 had a component of type C2 and C2 had
a component of type C1*.  I won't go into the details, but they were part of
a data structure implemented using a doubly-linked list.  Because of
performance problems I decided to change the data structure to use a skip
list.  To do this I had to change the classes so that C1 had a component of
type C2* and C2 had a component of type C1.  In C++ this was very easy to
do, and, because the classes were designed with the proper level of privacy,
the clients were entirely unaffected (although the implementation of C1 and
C2 had to be completely rewritten).

My point is that this is exactly a maintenance change, it's not that the
design was fundamentally broken.  And it was really easy to do in C++...

PS: One could argue that I could have pointers in both classes and be done
with it.  But I try to avoid dynamic allocation if possible.  And of course
pointers create the risk of unwanted sharing, i.e. more bugs.

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

From: Pascal Leroy
Sent: Friday, January 24, 2003  4:01 AM

Tuck commented:

> I also wonder how common it will be to consider introducing a circular
> dependence a typical "maintenance" activity.  Circular type dependence
> almost always implies some kind of recursive processing as well, so this
> doesn't seem like a "small" change.

Of course this discussion is similar to "I wonder how many people will be
impacted if we introduce this incompatibility".  The truth is we don't know
and we have no way to know.  In general however I think it's bad language
design to force users to follow a certain pattern if there is no compelling
reason to do so.

Also note that circular dependences are not restricted to data structures:
you may introduce a circular dependence because (in my example) you add in
P2 an operation that takes parameters of type T1 and T2 (assuming that the
types are tagged).

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

From: Pascal Leroy
Sent: Friday, January 24, 2003  4:19 AM

Jean-Pierre noticed:

> There is no circular dependency problem if all packages are nested within
one big package.
> The only new possibility of this solution is to separate (part of) the
specification.
> Separating the body was of course already possible.

Good point.  Actually, for tagged types, there is no circularity problem if
you are willing to play games with access-to-class-wide types:

    package Root is
    private
        type Type_1 is abstract tagged null record;
        type Access_Type_1_Class is access Type_1'Class;
        -- Similarly Type_2, Type_3, etc.
    end Root;

Now put all your code in children of Root, derive all your types from some
Type_n and use Access_Type_n_Class whenever you have to create circular
dependences.

This is starting to look pretty much like package prefixes to me.  I realize
that there are differences, but the two approaches share some of the same
drawbacks.  If we are to design a brand new language feature, maybe it
should have clear advantages over what can already be done with Ada 95.

Pascal

PS: Of course, in Ada 95 there is not much you can do in the case of
untagged types.

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

From: Robert A. Duff
Sent: Friday, January 24, 2003  7:18 AM

> Now put all your code in children of Root, derive all your types from some
> Type_n and use Access_Type_n_Class whenever you have to create circular
> dependences.

But then you have zillions of downward conversions scattered all over
the code.

> This is starting to look pretty much like package prefixes to me.  I realize
> that there are differences, but the two approaches share some of the same
> drawbacks.  If we are to design a brand new language feature, maybe it
> should have clear advantages over what can already be done with Ada 95.

By the way, my initial idea for solving the circular dependence problem
was based on this trick.  Add a way to declare "this abstract type has
only one type derived from it".  Check at link time.  And then make
downward conversions implicit -- it's safe, because you know the tag
must be correct.  So yes, the tagged type trick is related to package
prefixes.

> Pascal
>
> PS: Of course, in Ada 95 there is not much you can do in the case of
> untagged types.

You can do the same sort of trick for untagged types, if you're willing
to use unchecked conversions all over.  Yuck.

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

From: Tucker Taft
Sent: Friday, January 24, 2003  8:05 AM

Jean-Pierre noticed:

>There is no circular dependency problem if all packages are nested within
>one big package. The only new possibility of this solution is to separate
>(part of) the specification.

Yes, that is exactly what we are accomplishing.
And that is all that is really needed.  And note
that in general only *one* package needs to have
a little bit be physically nested, and that is
enough to allow all the others to be completely
separately compiled children.

>>Separating the body was of course already possible.

Right, but that still meant that the package spec was
huge, and growing without bound.  With having just
a nested "prefix," we only need to nest one (or a very
small number) of sub-package prefixes physically within the
parent package.  So the parent package spec does not
grow without bound as you add more sub-packages into
the circularity.

Pascal wrote:

> This is starting to look pretty much like package prefixes to me.  I realize
> that there are differences, but the two approaches share some of the same
> drawbacks.  If we are to design a brand new language feature, maybe it
> should have clear advantages over what can already be done with Ada 95.

I don't see this.  Nesting a single package prefix could break circularity
in many systems, without any additional, artificial, downward
(or unchecked) conversions thrown in.

That seems like a *clear* (huge? ;-) advantage over Ada 95.
The fact that it is accomplished with such a modest change
to the syntax and semantics seems like a feature, not a bug.

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

From: Robert I. Eachus
Sent: Friday, January 24, 2003  8:05 AM

>My point is that this is exactly a maintenance change, it's not that the
>design was fundamentally broken.  And it was really easy to do in C++...
>
And it should be similarly easy in Ada, no question.  My point was that,
when as in this case you have two types (classes) C1 and C2 that are of
equal precedence the program structure has to reflect that fact, or you
run into implementation and maintenace difficulties.  If  you make it
visible at a design, not an implementation level that C2 is a component
of C1, then your maintenance change requires changing the design.

If the design treats the classes as of equal precedence, however, the
change you made would occur only (in Ada) in the private parts and
bodies and bodies of the packages that exported the two abstractions.
 This is the real problem that we are trying to address.  Right now Ada
forces you to choose an asymmetric design, and at least 50% of the time,
that design will be wrong.

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

From: Randy Brukardt
Sent: Friday, January 24, 2003  7:51 PM

> Now put all your code in children of Root, derive all your types from some
> Type_n and use Access_Type_n_Class whenever you have to create circular
> dependences.

And this is fairly close to what we did in Claw. The difference being that
we made the root types visible and added some of the root operations (such
as destruction) at this level. That cut down the number of explicit
conversions needed dramtically, but at the cost of putting a lot of code in
the root.

For CBuild, I simply used names rather than links (in part because there is
no common parent to use), but that has some problems as noted.

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

From: Randy Brukardt
Sent: Friday, January 24, 2003  8:15 PM

Tucker said:

> That seems like a *clear* (huge? ;-) advantage over Ada 95.
> The fact that it is accomplished with such a modest change
> to the syntax and semantics seems like a feature, not a bug.

Please stop claiming this is a "modest" change without proof. I remain
skeptical, after all "type stubs" were very simple (but ended up with a
bunch of strange availability rules). And the impact on elaboration and
freezing and visibility remains to understood.

You're going to have to show me the wording before I can sign up for any
change to visibility. And even if not a word of visibility needs to change
(which I sincerely doubt), it is going to be a significant change inside of
compilers. It might be easier to add a third part than adding the second,
but I doubt it will be very much easier.

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

From: Ed Schonberg
Sent: Sunday, January 26, 2003  8:11 AM

The simplest way to avoid freezing and elaboration issues is to restrict
the contents of the "child package abstract" (does this have a name yet?)
to contain only incomplete type declarations and access type declarations.
This is what is needed to solve the circular dependence problem. Anything
else can only be a can of worms. I concur with Randy that anything that
touches on visibility is a major disruption to compilers, not a neat bounded
change. Only a minimalist solution has a chance here.

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

From: Tucker Taft
Sent: Sunday, January 26, 2003  10:20 AM

Randy writes, and Ed reiterates:

>  Please stop claiming this is a "modest" change without proof.

Here is not a proof, but perhaps a way of looking at it
that might make it seem modest (or at least less frightening).
The idea is to make the child into a "normal" nested package,
and put its body into a subunit.  Now create a stub in
the middle of its body, and think of the code preceding
the stub as the rest of the spec of the child, and
the code following the stub as the "true" body of
the child.  This situation should approximate the visibility
and freezing rules that would be associated with
this proposal.

For example, imagine the following, which is almost legal in
Ada 95.  [The thing that is not legal is that we have allowed
the deferred incomplete type to be in the visible part
of C.  This might be a reasonable relaxation of the rules
anyway, though that is a separate (but related!)
topic for conversation... ;-)]:

package P is
    ...
    package C is
       -- this is like the "prefix" of the spec of C
        type Some_Enum is (Red, Green, Blue);
        type T(E : Some_Enum);  -- deferred incomplete type

        type T_Ptr is access all T;
        for T_Ptr'Storage_Pool use ...;

        function Whatever return T_Ptr;
    end C;
    ...
end P;  -- freezing happens no later than here
         -- for anything declared in "prefix" of C

package body P is
    package body C is separate;
    ...
end P;

separate(P)
package body C is
    -- This is like the "main" part of the spec of C
    type T(E : Some_Enum) is record
        X : Integer;
    end record;

    procedure Op1(Y : in out T);
    procedure Op2(Z : in T);

    package Viewpoint is end;
    package body Viewpoint is separate;  -- Freezing happens here for
                                         -- "main" part of spec of C

    -- And here starts the "body" of C.

    function Whatever return T_Ptr is ...
    procedure Op1(Y : in out T) is ...
    procedure Op2(Z : in T) is ...
    ...
end C;


separate(P.C)
package body Viewpoint is
    -- What is (directly) visible here from P.C is what will be
    -- (selectively) visible here in units that "with" P.C.
    ...
end Viewpoint;

As you can see, we have partitioned P.C into three parts,
the first part physically nested in the spec of P (the "prefix"),
the second part preceding an external viewpoint (the "main" part
of the spec), and the third part following the external
viewpoint (the "body").

--------

And now for that other conversation -- allowing a deferred
incomplete type to be in the visible part seems a reasonable
relaxation in general, since all of these type-stub/package abstract/
package prefix are making uncompleted incomplete types more widely visible.
They were already visible to child packages in Ada 95, so it
probably doesn't represent an implementation burden.
I suppose the only problem is that it might be simply
a "bug" that the user forgot to complete the incomplete type.
But it is a bug that will be caught when the body is compiled,
so that seems pretty reasonable.

Another similar relaxation that many customers and non-paying
users alike have wished for has been the ability to complete
a deferred constant in a package body.  This is "standard fare"
in C and C++, and is extremely useful from a separate compilation
point of view.   Again, this might mask a bug where the user
simply forgot to complete the constant, but it would be caught
as soon as the body is compiled.

In any case, it seems we certainly want to allow such things
in package abstracts/prefixes (if we go that route), since we
know the abstract/prefix represents only part of the spec.
But it seems that once you go that far, you might as well
grant the added flexibility to users of more "mundane"
package specs and bodies.

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

From: Dan Eilers
Sent: Tuesday, January 28, 2003  2:52 PM

It looks to me like we can combine the "type stub" proposal with
Tucker's "child prefix" proposal, and get the best of both worlds,
without the negatives of either.

The big negative of "type stub" is that the type stub names a unit
that isn't previously declared.

The big negative of "child prefix" is that it impacts client code
by changing all type references from P.T to P.child.T.  Only the
clients that need the full type (e.g. for declaring objects) should
have to say P.child.T.

The "prefix" proposal addresses the first negative by:
  1) restricting the full type to be in a child unit
  2) giving a "forward" declaration of the child in its parent.

By requiring the full type to be in a child unit, there
is also no complexity associated with the case where the
child could be with'd but not the parent.

The "type stub" proposal addresses the second negative by
declaring the type stub directly within the parent.

So if we combine the two proposals, we get:

package P is
    package C;    -- or whatever syntax we like for a child unit stub
    type T is separate in C;
    type T_Ptr is access T;
end P;


instead of:

-- type stub proposal
package P is
    type T is separate in P.C;
    type T_Ptr is access T;
end P;

or:

-- child prefix proposal
package P is
    package C is separate
        type T;
        type T_Ptr is access T;
    end C;
end P;


Note: I am somewhat reluctant to propose using the keyword "separate"
in a child unit stub, since "separate" generally implies that the stub
can't be with'd.

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

From: Tucker Taft
Sent: Tuesday, January 28, 2003  2:53 PM

Unfortunately this doesn't address the problem
where all types are called "Object" and the package
name is effectively part of the type name.
This was considered a common enough idiom at SIGAda 2002
that I really think we need to solve it.

I think a structural advantage to the child prefix proposal as is
is that it tends to lead to all the packages that participate
in a circular dependence being in the same subsystem, rather
than just a random collection of root packages.

Since it is relatively painless to add a layer to move a set
of related packages into a subsystem, this seems like
a small price to pay to allow circular dependence.  The only
changes are in "with" clauses, and perhaps a "use" for
the subsystem as a whole.  Renames can also be used to
make the packages visible with their old library name.

Note that we inserted the "Ada" layer into the Ada 83 run-time
library, with no significant upward incompatibilities, thanks
to library-unit renaming.

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

From: Dan Eilers
Sent: Tuesday, January 28, 2003  5:24 PM

Tucker wrote:
> Unfortunately this doesn't address the problem
> where all types are called "Object" and the package
> name is effectively part of the type name.
> This was considered a common enough idiom at SIGAda 2002
> that I really think we need to solve it.

OK, I worked out an example which makes this more clear.

Given the canonical example of Employees and Departments
expressed using the original "package abstracts" of AI-10217:

    package abstract Employees is
        type Employee;
        type Emp_Ptr is access all Employee;
    end Employees;

    package abstract Departments is
        type Department;
        type Dept_Ptr is access all Department;
    end Departments;

    with Departments abstract;
    package Employees is
        type Employee is private;
        type Emp_Ptr is access all Employee;
        procedure Assign_Employee(E : access Employee;
                                  D : access Departments.Department);
        function Current_Department(D : access constant Employee) return
            Departments.Dept_Ptr;
    end Employees;

    with Employees abstract;
    package Departments is
        type Department is private;
        type Dept_Ptr is access all Department;
        procedure Choose_Manager(D : access Department;
                                 Manager : access Employees.Employee);
    end Departments;


This would be expressed in my proposed hybrid type-stub/prefix form as:

    package Employees is
        package Extension;             -- new child package stub
        type Employee is separate in Extension;
        type Emp_Ptr is access all Employee;
    end Employees;

    package Departments is
        package Extension;             -- new child package stub
        type Department is separate in Extension;
        type Dept_Ptr is access all Department;
    end Departments;

    with Departments;
    package Employees.Extension is
        type Employee is private;
        procedure Assign_Employee(E : access Employee;
                                  D : access Departments.Department);
        function Current_Department(D : access constant Employee) return
            Departments.Dept_Ptr;
    private
        type Employee is record
           dept: Departments.Dept_Ptr;
        end record;
    end Employees.Extension;

    with Employees;
    package Departments.Extension is
        type Department is private;
        procedure Choose_Manager(D : access Department;
                                 Manager : access Employees.Employee);
    private
        type Department is
           emp: Employees.Emp_Ptr;
        end record;
    end Departments.Extension;


A user would probably want to use library-level renaming to avoid having
to refer to the Extension child unit in the clients.

Calling everything "Object" works fine, resulting in:

    package Employees is
        package Extension;             -- new child package stub
        type Object is separate in Extension;
        type Emp_Ptr is access all Object;
    end Employees;

    package Departments is
        package Extension;             -- new child package stub
        type Object is separate in Extension;
        type Dept_Ptr is access all Object;
    end Departments;

    with Departments;
    package Employees.Extension is
        type Object is private;
        procedure Assign_Employee(E : access Object;
                                  D : access Departments.Object);
        function Current_Department(D : access constant Object) return
            Departments.Dept_Ptr;
    private
        type Object is record
           dept: Departments.Dept_Ptr;
        end record;
    end Employees.Extension;

    with Employees;
    package Departments.Extension is
        type Object is private;
        procedure Choose_Manager(D : access Object;
                                 Manager : access Employees.Object);
    private
        type Object is
           emp: Employees.Emp_Ptr;
        end record;
    end Departments.Extension;


Reorganizing to use a new root package Directory, we would get:

    package Directory is
        package Employees;       -- new child package stub
        type Employee is separate in Employees;
        type Emp_Ptr is access all Employee;
        package Departments;     -- new child package stub
        type Department is separate in Departments;
        type Dept_Ptr is access all Department;
    end Directory;

    package Directory.Employees is
        type Employee is private;
        procedure Assign_Employee(E : access Employee;
                                  D : access Directory.Department);
        function Current_Department(D : access constant Employee) return
            Directory.Dept_Ptr;
    private
        type Employee is record
           dept: Directory.Dept_Ptr;
        end record;
    end Directory.Employees;

    package Directory.Departments is
        type Department is private;
        procedure Choose_Manager(D : access Department;
                                 Manager : access Directory.Employee);
    private
        type Department is
           emp: Directory.Emp_Ptr;
        end record;
    end Directory.Departments;

which also works fine, except that as you point out, it doesn't allow
type Employee and Department to both be named Object.

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

From: Tucker Taft
Sent: Wednesday, January 29, 2003  8:55 AM

Here is another step toward simplification,
inspired in part by Dan Eiler's recent thoughts.
It also happens to be very similar to a proposal
consided during the Ada 9X process, with the crucial
difference that it would be allowed in the visible part.

Basically, the propsal is to allow an incomplete type declaration to
use a (singly) "dotted" name for the type being introduced:

E.g.:

package P is

     type C.T;  -- incomplete type, specifying that
                -- full type will be in a nested or child
                -- package.

     type T_Ptr is access C.T;  -- if desired

      ...

end;

package P.C is
    type T is ...  -- full type

    subtype T_Ptr is P.T_Ptr;  -- if desired

    ...

end P.C;

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

That's it, except of course we all seem to agree that the
tagged incomplete type is a good idea, and that incomplete
types should be allowed to be completed by a private type.

The major change relative to the child package prefix proposal
is that we have eliminated the new kind of program unit.

How does this compare with other proposals?

"with type" had the following problems:
1) New kind of "with" clause
2) Dependence that isn't really a dependence
3) with-type clause could appear anywhere, making
    it difficult to know when to check that the
    full type existed and matched the with-type.

"package abstracts" had the following problems:
1) Required a new kind of program unit and with clause
2) Special rules for elaboration order and corresponding
    restrictions on what could appear in the abstract, including
    possibly nested abstracts, etc.
3) Unclear rules about what part of the parent unit the
    abstract of a child got to see (none, abstract only,
    full spec).
4) Because a package abstract is optional, it has some
    of the same headaches associated with optional
    specs on library unit subprograms.

"type stubs" had the following problems:
1) Multiple type stubs for the same type makes it
    unclear exactly when the check is to be performed
    that the package completes the type stub.
2) Trouble when all types have the same name (e.g. Object).
3) Lack of mention in a context clause of the enclosing package,
    leading to a new kind of with clause, leading to a new
    kind of dependence
4) Type stub and full type didn't have the same fully expanded
    name, making for tricky rules for when and where the name
    associated with the type stub could be used to represent
    the full type.  Subtle "availability" rules.


"child package prefixes" had the following problems:
1) Syntax suggests that feature would make sense for
    root packages, but a seemingly "arbitrary" restriction
    only allows prefixes for child (or nested) packages.


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

This proposal does not have any of the above problems, though
of course it does have some problems.  Here are some
of the problems, with some of the remediating factors:

1) It restricts this new capability to types that are in child
    or nested packages.

Remediating factor: Since types are not separately compilable,
it creates less of an expectation that the feature should work
for types in root packages.  Furthermore, it is unlikely the
user will think of it that way.  Rather, the way it reads to a user
is that in the past, I could use incomplete types to create
mutually recursive types in a single package.  Now I can use
these new more flexible incomplete type declarations to create
mutually recursive types that involve a package and its child
or nested packages.

2) It introduces the name of a child/nested package as part of
    an incomplete type declaration, leading to a "ghost" package
    (as Pascal has called it).

Remdiating factor: This ghost package exists only in the scope
where it will ultimately appear for real as a nested or
child package, rather than having to be constructed at each
"with-type" clause.  One of the problems with the ghost packages
required by the with-type clause was that different units might
have different sets of with-type clauses, so this ghost package might
have more or fewer incomplete types declared inside it, depending on
the number of with-type clauses in scope.  And then if you "with"
the "real" package, it somehow has to be merged with and/or checked
against the various ghost packages.  In this proposal, the ghost
package is created at the first such incomplete type declaration,
and only can grow if there are more incomplete type declarations
appearing in the enclosing package spec.  There is never more than
one "ghost" package for a given nested/child package, and every
one sees the "same" ghost package.

3) There is no way to "pre"-declare an access type that ends up
    inside the nested/child package.

Remediating factor: You can declare the access type in the enclosing
package, and then use a subtype or derived type declaration to put
an equivalent/interconvertible access (sub)type into the nested/child
package, if desired.

As usual, fire away...

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

From: Arnaud Charlet
Sent: Wednesday, January 29, 2003  9:11 AM

This last proposal has definitely many interesting capabilities and
addresses several issues.

However, I don't think (or at least I don't see how) it addresses the issue
of generating "bindings" to API written in existing languages.

Suppose you have e.g. two header files, or two java classes, not under
the same hierarchy, with type definitions referencing one another. How would
you automatically and "naturally" translate these with your proposal ?

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

From: Robert Dewar
Sent: Wednesday, January 29, 2003  9:46 AM

That certainly seems like an appropriate criterion. Certainly we want a
solution that works at least as well in this regard as the current
version of WITH TYPE that we have implemented, and routinely use for
this purpose.

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

From: Pascal Leroy
Sent: Wednesday, January 29, 2003  9:58 AM

Agreed, and that's what makes me uncomfortable with the notion of tying
incomplete types with child units.  In real life you have many constraints on
how you organize your compilation units, and Tuck's proposals all add yet
another contraint.  I fear that in a number of cases this extra constraint will
make the set of solutions empty.

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

From: Ed Schonberg
Sent: Wednesday, January 29, 2003  10:08 AM

But why is the incomplete declaration tied to a child unit?

Tucker proposes:

>   Basically, the propsal is to allow an incomplete type declaration to
>   use a (singly) "dotted" name for the type being introduced:

>   E.g.:

>   package P is
>
>        type C.T;  -- incomplete type, specifying that
>                   -- full type will be in a nested or child
>                   -- package.

I don't see why a child ghost is preferable to an arbitrary ghost! The
declaration introduces the name of a unit that will eventually be
compiled and provide the completion for the type. Why the restriction to
a member of the family?

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

From: Pascal Leroy
Sent: Wednesday, January 29, 2003  10:08 AM

> That's it, except of course we all seem to agree that the
> tagged incomplete type is a good idea, and that incomplete
> types should be allowed to be completed by a private type.

Tagged incomplete types are certainly a good idea.

Completing an incomplete type by a private is an appealing idea from a language
design standpoint, but it frightens the implementer in me.  In essence, I fear
that having three-part types is going to break a lot of invariants in
implementations.  We have a zillion places in our compiler where we do a very
complex analysis to decide what we know about a type at a particular place
(i.e., whether we see the partial view or the full view) and I cannot believe
that other compilers don't have similar contraptions.  Changing this to deal
with three-part-types is going to be a lot of work.

Ideally I would love to merge the partial view and the incomplete view (and
stick to two-part types), but I have not been able to come up with sensible
ideas on how to do that.

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

From: Tucker Taft
Sent: Wednesday, January 29, 2003 10:31 AM

Ed Schonberg wrote:
> Pascal writes:
>
>> Agreed, and that's what makes me uncomfortable with the notion of tying
>> incomplete types with child units.  In real life you have many constraints on
>> how you organize your compilation units, and Tuck's proposals all add yet
>> another contraint.I fear that in a number of cases this extra constraint will
>> make the set of solutions empty.

I have suggested that it is always relatively "easy" to introduce
an extra layer at the "top" of a (sub)system, as indicated
by our introduction of "Ada." in Ada 9x.  Can you give some
examples where this is not so easy, so I can appreciate the
issue better?

> But why is the incomplete declaration tied to a child unit?
>...
>
> I don't see why a child ghost is preferable to an arbitrary ghost! The
> declaration introduces the name of a unit that will eventually be
> compiled and provide the completion for the type. Why the restriction to
> a member of the family?

Because having multiple ghosts for the same package creates
significantly more problems, and the "completing" package
is unaware of the existence of these ghosts, and hence
checking of appropriate completions has to be performed
by users of the type, rather than by the declarer of the
type.

Both of the proposals I have made recently eliminate any
special work on the part of the users of such an incomplete
type.  All of the work is localized to the place where the
type is completed, since it is guaranteed to see and be
aware of the incomplete type declaration.

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

From: Arnaud Charlet
Sent: Wednesday, January 29, 2003 10:44 AM

> I have suggested that it is always relatively "easy" to introduce
> an extra layer at the "top" of a (sub)system, as indicated
> by our introduction of "Ada." in Ada 9x.  Can you give some
> examples where this is not so easy, so I can appreciate the
> issue better?

I don't think an automated tool that would take e.g. existing C or Java
headers would be able to easily introduce an extra layer and put every
needed circular dependence in the parent package. This would require a
global processing of all possible units, and would mean having to regenerate
everything each time a new unit is added. It would also mean lots of
unrelated declarations in the parent package.

Unless I am missing something, this is definitely not a very attractive
solution if you take the foreign language bindings into account.

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

From: Tucker Taft
Sent: Wednesday, January 29, 2003 11:06 AM

Robert Dewar wrote:
 >>Suppose you have e.g. two header files, or two java classes, not under
 >>the same hierarchy, with type definitions referencing one another. How would
 >>you automatically and "naturally" translate these with your proposal ?
 >
 >
 > That certainly seems like an appropriate criterion. Certainly we want a
 > solution that works at least as well in this regard as the current
 > version of WITH TYPE that we have implemented, and routinely use for
 > this purpose.

I agree that "with type" is the simplest for binding generators,
but we have seen the various technical problems associated
with this proposal, when we try to nail down full
implementation-independent semantics for it.

As I mentioned in an earlier note, I personally now prefer "with type"
(for incomplete types only, not for access types) to type
stubs and package abstracts, but there is still the somewhat
tricky rules required having to do with who checks that
the full type exists and matches the with-type (i.e. is tagged
if specified), and the issue of multiple distinct package
"ghosts" that have to be correlated.

In any case, I believe that a binding generator for Java
could relatively easily add the appropriate incomplete type declarations
(required by this newest proposal) into the enclosing package when
necessary.  Certainly in Java it is absolutely standard practice to put
every class of any importance in an enclosing package, so there would
always be a place to "drop" these incomplete type declarations
in the generated Ada.  It might be a bit of an "art" to
put as few incomplete type declarations as possible in the
enclosing package, but that is more of an optimization than
a requirement.

For C, it would probably be natural (or at least not unnatural)
to create a binding which involved multiple C header files as a
package hierarchy, with a root package where these incomplete type
declarations could be dropped as needed.  In C++, namespaces
correspond to Java's classes, and it is becoming more common to
declare C++ classes in namespaces, so again, the package representing
the namespace would be a natural place to declare the
incomplte types for "<classname>.Object" or whatever naming
convention is used for C++ classes.

Note that in C and C++, it is probably more "obvious" than
in Java when an incomplete type declaration is needed, since
C/C++ have a corresponding notion of incomplete type references.
A type from another header that is referenced with such an
incomplete type reference would be an obvious candidate to
be have an Ada incomplete type declaration for it placed in
the enclosing package.

I don't think it is a bad tradeoff to make binding generators
a bit more complicated (or perhaps even require a small amount
of manual fixup) to keeping the language and the compilers
simpler.

For me, at least, my two favorite proposals are now "with type"
(for incomplete types only) and this newest one.  They both
have the nice effect that there is exactly one fully expanded
name for the type, so those using types all called "Object"
or whatever have no problems.  Also, we don't have to specify
complex rules about when one name means the same thing as
some other name for the "same" type.

This newest proposal has the added benefit that there is at most
one incomplete type for a given complete type, rather than one
created for each "with type."  Furthermore, the complete type
knows that the incomplete type is visible to other units, in
as much as that might affect representation of pointers (given
the possibility of pointer type conversion).
Admittedly, it makes binding generators more complicated, but
I believe it simplifies implementations, and avoids introducing
a new kind of context clause or a new kind of unit dependence.

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

From: Dan Eilers
Sent: Wednesday, January 29, 2003 12:08 PM

Arno wrote:
> However, I don't think (or at least I don't see how) it addresses the issue
> of generating "bindings" to API written in existing languages.
>
> Suppose you have e.g. two header files, or two java classes, not under
> the same hierarchy, with type definitions referencing one another. How would
> you automatically and "naturally" translate these with your proposal ?

You would basically have two choices:

1) invent a parent to hold the type stubs; or
2) split the package into two parts, one part being the parent of the other,
   with the type stubs in the parent, and use a library-level renames to
   rename the child to what you want the clients to use.


Robert Dewar wrote:
> That certainly seems like an appropriate criterion. Certainly we want a
> solution that works at least as well in this regard as the current
> version of WITH TYPE that we have implemented, and routinely use for
> this purpose.

Well, the nicest solution for the user is just to allow specs to with
each other, as other languages do.  With type is the second nicest
user solution, but was abandoned a long time ago for a number of reasons
(see Randy's enumeration).  Separately compiled package abstracts are
the third nicest user solution, but they have tool impact due to a
new kind of compilation unit.  That leaves putting the abstract either
in a parent, or in a child, or in an unrelated unit.

Putting the abstract in an unrelated unit prevents having to invent
a parent, but was rejected by users at the SigAda meeting, for violating
the rule that you can't normally refer to an undeclared unit.

Putting the abstract in a child unit also prevents having to invent
a parent, but violates the rule that you can't normally compile a child
unit before compiling its parent.

Putting the abstract in a parent unit is the current proposal.  It is
probably the least convenient for the user of the proposed solutions,
since a parent generally has to be invented or the child renamed, but
it is the most consistent with Ada's general design principles.

Ed Schonberg wrote:
> I don't see why a child ghost is preferable to an arbitrary ghost!

Because it is consistent with the Ada design principle that child units
are the mechanism for package extension.

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

From: Jean-Pierre Rosen
Sent: Wednesday, January 29, 2003 12:37 PM

Since we are furiously inventing...

(I thought I submitted this before, but since nobody reacted, it must have been
lost - or is it that stupid that nobody even cared to respond? :-).

Taking back the package abstract idea, but as a context clause:

with package Foo is
   type T;
end Foo;
package Bar is....

i.e. each user of a package abstract must repeat it as a context clause,
therefore avoiding the new compilation unit issue.

There would be a burden at link time, since it is necessary to check that the
actual Foo fulfills the promises of all package abstracts.

Note that different packages may choose different abstracts from Foo (if it
provides several types f.e.) which may not be a bad thing. I.e. each unit makes
its own abstract of a complex package, importing only what's needed.

No restriction to child unit, so it would address the concern of Java specs.

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

From: Randy Brukardt
Sent: Wednesday, January 29, 2003  2:02 PM

> package P is
>
>      type C.T;  -- incomplete type, specifying that
>                 -- full type will be in a nested or child
>                 -- package.
>
>      type T_Ptr is access C.T;  -- if desired
>
>       ...
>
> end;

I dislike this syntax, for the simple reason that it requires a change to
Type_Declaration, rather than to Type_Definition. That ups the ante for
implementation considerably (Janus/Ada at least, processes those two
productions separately). Let me suggest another syntax:

     type T is separate in C;

:-)

This immediately shows us that this is type stubs with restriction on the
stub package; nothing more and nothing less.

(Indeed, this is slightly better than Tucker's proposal, because there are
no ghost packages.)

The restriction seems to buy us two things:

    1) Since the completion has to (by definition) see the stub, the
       completion rules are substantially simplified. (Perhaps to
       non-existent.)
    2) Since the completion has to be in the child package, and child
       packages already can appear without any notation in their parent,
       we've defined away the dependence in the context clause concern.
       (I doubt that will really make the people who complained happy,
       but that's the solution.)

Of course, it also continues to have the problem of forcing a design into
child packages whether that is desired or not.

We could get the advantages of (1) and not have the requirement to force the
design, by requiring that the completion with the package containing the
stub. That would have to be a post-compilation rule (unfortunately), but it
would eliminate virtually all of the completion complexity. [While it would
be possible for packages with different visibility on the stub to meet,
since withs are non-transitive, we know that withs are transitive for the
purposes of type matching. Thus, anything with visibility on the completion
would have "know" about the stub, so type compatibility would remain as it
currently is in implementations (such as a compare of type numbers in
Janus/Ada).]

Of course, that does not do anything to address the user concern about
showing dependence in the context clause. That could be addressed as in
alternative #5, or we could declare it a red herring and move on (as some
people here seem to prefer to do).

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

From: Randy Brukardt
Sent: Wednesday, January 29, 2003  2:10 PM

> That certainly seems like an appropriate criterion. Certainly we want a
> solution that works at least as well in this regard as the current
> version of WITH TYPE that we have implemented, and routinely use for
> this purpose.

But it's also an impossible criterion. I don't think that any of the
proposals considered (INCLUDING with type) meets it. That's because the GNAT
with type allows withs of access types, which we had to eliminate from any
proposal because of various problems. And I expect that would be the
keystone to any "easy" importation of Java or C++ classes.

Therefore, with ANY proposal that the ARG has considered requires the
introduction of a second package - either an abstract (or prefix), or a real
package containing a type stub (which includes Tucker's most recent "parent"
proposal).

And thus, the translator of the classes is going to have to do some
restructuring.

In any case, I think it is important that we not lose sight of the fact that
whatever we choose needs to be natural in an all-Ada design. Ada programmers
have had this problem for 20 years, and generally have had to bloat up
packages to deal with it. It would be pretty silly to adopt something simply
because it makes copying Java classes easy (unless we believe that there
won't be any new Ada designs -- in which case, we're all wasting our time on
this whole exercise).

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

From: Tucker Taft
Sent: Wednesday, January 29, 2003  3:10 PM

> I dislike this syntax, for the simple reason that it requires a change to
> Type_Declaration, rather than to Type_Definition.

Is this really that big a deal?  Compared to all the other options?

> ... That ups the ante for
> implementation considerably (Janus/Ada at least, processes those two
> productions separately).  Let me suggest another syntax:
>
>      type T is separate in C;
>
> :-)

But what does this mean?  Is the full name for the type "P.C.T" or is it "P.T"?
The fact that I have to ask this question makes me think it is an error prone
syntax.

> This immediately shows us that this is type stubs with restriction on the
> stub package; nothing more and nothing less.
>
> (Indeed, this is slightly better than Tucker's proposal, because there are
> no ghost packages.)

I have lost you.  Don't you still have to create "C", or are you saying
the full name of the type is "P.T"?  If the latter, then you are
back to the situation where, presumably, in some cases P.T is an
incomplete type, and in other somewhat-difficult-to-define cases,
P.T is a "complete" type.  Or are you saying that P.T is *always* an
incomplete type, even if you "with" P.C?

To me it is this issue of when or if "P.T" is a complete type that
is the fundamental problem with type stubs which introduce their
own name.

> The restriction seems to buy us two things:
>
>     1) Since the completion has to (by definition) see the stub, the
>        completion rules are substantially simplified. (Perhaps to non-existent.)
>     2) Since the completion has to be in the child package, and child packages
>        already can appear without any notation in their parent, we've defined away
>        the dependence in the context clause concern. (I doubt that will
>        really make the people who complained happy, but that's the solution.)

I presume you are agreeing that the "type C.T;" proposal has the same
two advantages.

> Of course, it also continues to have the problem of forcing a design into
> child packages whether that is desired or not.
>
> We could get the advantages of (1) and not have the requirement to force the
> design, by requiring that the completion with the package containing the
> stub.

This sentence no verb. ;-)

> ... That would have to be a post-compilation rule (unfortunately), but it
> would eliminate virtually all of the completion complexity. [While it would
> be possible for packages with different visibility on the stub to meet,
> since withs are non-transitive, we know that withs are transitive for the
> purposes of type matching. Thus, anything with visibility on the completion
> would have "know" about the stub, so type compatibility would remain as it
> currently is in implementations (such as a compare of type numbers in
> Janus/Ada).]

Unfortunately, I cannot understand this idea presumably due to lack
of some key words in the sentences.

> Of course, that does not do anything to address the user concern about
> showing dependence in the context clause. That could be addressed as in
> alternative #5, or we could declare it a red herring and move on (as some
> people here seem to prefer to do).

What is alternative #5, in a few words?

Other than the detailed syntax, are you saying you like the semantics
of "type C.T;", or are you saying you prefer the restricted-to-children
type stub where the full name is "P.T;" of the incomplete type, while the
complete type name is "P.C.T"?

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

From: Randy Brukardt
Sent: Wednesday, January 29, 2003  4:21 PM

> Unfortunately, I cannot understand this idea presumably due to lack
> of some key words in the sentences.

The only words that I saw that were missing was "is". I've been working on
the search engine, where words like that are ignored, and I've taken it a
bit too far... :-)

Anyway, the basic idea is that P.T is always incomplete; P.C.T is complete
and matches P.T trivially because it always knows about P.T. Thus the
completion rules are simplified. (That does mean that P.T and Q.T don't
match each other if both are stubs of the same completion; I don't think
that matters in any of the canonical uses we've sketched out.)

I definitely didn't work out the details on this one - one fully worked out
alternative per meeting is my limit. :-)

> > Of course, that does not do anything to address the user concern about
> > showing dependence in the context clause. That could be addressed as in
> > alternative #5, or we could declare it a red herring and move on (as some
> > people here seem to prefer to do).
>
> What is alternative #5, in a few words?

Some sort of context item to introduce a package name solely for use in type
stubs. I had proposed
    abstract of P;
but the semantics are the same no matter what the syntax.
    with separate P;
works as well.

> Other than the detailed syntax, are you saying you like the semantics
> of "type C.T;", or are you saying you prefer the restricted-to-children
> type stub where the full name is "P.T;" of the incomplete type, while the
> complete type name is "P.C.T"?

I think I like original type stubs the best. :-)

I was just trying to figure out if your proposal was significantly different
than type stubs, and it didn't seem like it.

If I had to rank these by alternative number (and giving prefixes #6 and
this latest one #7), I'd say:  4 (type stub alone), 5 (type stub with
context marker), 7, 6, 1 (fixed up with type, any syntax).

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

From: Tucker Taft
Sent: Thursday, January 30, 2003  8:32 AM

There seems to be some feeling that type stubs
were almost right, and we should either leave
them as is, or add some kind of special context
clause such as "separate with ..." and be done with it.

Personally, I don't feel that way anymore.  Here are some
reasons why:

1) Type stubs look and feel like an add-on to the language.
    Nothing about them looks natural to my eyes.  As a language
    designer/enhancer, I always want the new features to look
    like they were "always" there, so the language is seamless
    and there is no obvious dividing line between old and
    new features.

2) Type stubs are not necessarily "seen" by the type completer.
    I think this could have negative implications for compilers
    like GNAT that have multiple representations for access types
    (access-to-unconstrained array can be thick or thin, and I
    presume there is no easy way to convert a thick pointer to a
    thin one).  Of course GNAT itself doesn't have this particular
    problem with their existing "with type" implementation, because
    they "peak" at the actual type declaration at the time of
    processing a "with type."  I suppose this same trick could
    be used for type stubs, but requiring "peaking" at the
    full type seems generally unwise, and has interesting
    implications from a recompilation point of view.

3) Type stubs seems to require a particular "idiom" of use
    that makes it seem clear that some kind of package "prefix"
    or "abstract" is what we *really* wanted but couldn't somehow
    bring ourselves to provide.  To be specific, we
    have said that to deal with cases where most types have
    the same simple name (e.g. "Object"), you should use an
    idiom where a separate package is created to hold the
    type stub.  In fact, there seems to be some sense that this
    is a good idiom even if the type names aren't all the same.
    If this is really true, then it is clear to me that the
    type stub feature we designed is not the right solution,
    and a package prefix/abstract would be better.

4) Type stubs have the unfortunate situation where the
    same type has two different fully expanded names.  This
    creates numerous problems and confusions for specifying the
    rules, implementing the rules, and understanding the rules
    relating to when the two types are the same and when they
    are different. With the other approaches, there is only one
    fully expanded name for the type, and the usual 8.3(19) hiding rule
    that says a completion hides the prior declaration from all
    visibility within its scope, will generally be adequate to
    decide whether you have an incomplete type or a full type.

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

Of the other approaches that still seem viable to me,
"with type," package prefix/abstract (including the
stand-alone case), and "type C.T;" incomplete types:
a) "with type" has odd dependency semantics (dependence
    without a real dependence) and the completer doesn't
    "see" the incomplete type(s)
b) package prefix/abstract feels like a big change, requiring a new
    kind of program unit, a new kind of context clause, and non
    obvious rules about what part of the parent unit a child
    prefix/abstract can see.  Admittedly, the package prefix is
    probably the most powerful and flexible.
c) "type C.T;" seems like a natural outgrowth of two basic facts:
     i) the incomplete type declaration is the fundamental way
        of supporting mutually dependent types in Ada, but it
        is limited to only working within a single package spec;
     ii) child packages are the fundamental way of splitting a large
        abstraction into smaller, more manageable parts, but they are
        limited in that mutually dependent types cannot cross
        these pieces of the abstraction.

Obviously the above analysis is biased by what feels to me
to be the simplest "good" solution.  The major objection to
the more flexible incomplete type declaration seems to be that
it might not just "drop" into existing code.  But there is no
existing code that actually solves the mutually dependent
type problem.  There are only a collection of workarounds.
It seems unwise to require that any "real" solution to the problem
be able to simply drop easily into all existing workarounds.

There is no rule that the existing workarounds have to overnight
switch to using every new feature that might have obviated
the workaround.  It is like in Ada 95 -- clearly tagged types are
a nice solution to the problem of variant records and case
statements growing larger and larger as a data abstraction
gets more complex.  But to take advantage of tagged types,
you really have to restructure everything.  So there are
plenty of people still using variant records, for historical
reasons, or because they are still waiting for the mutually
dependent type problem to be solved before they "jump" to
tagged types.  I don't think that means we should have designed
tagged types so they could easily slip into all code that was
using variant records before.

We have to be focused on the person developing a new abstraction,
and how the language can be enhanced in modest ways to
enable that person to develop the abstraction without having
to stand on their head.  The old abstractions that were built
by standing on your head will probably always look like that,
until there is the time and money to redesign them to take best
advantage of new language capabilities.

My final word is to try to answer "why the change of heart"?  Presenting
the various Ada 200Y proposals to SIGAda '02 was generally a
reconfirming experience, making me feel that we were generally
on the right track.  However, the type stub proposal received
more negative reaction than anything else.  This made me step
back a bit from the proposal and try to look at it with the
perspective of an outsider.  I concluded that this proposal
seemed to be suffering from the results of "group think."

Group think is where a relatively isolated group (e.g. the ARG)
spends a very long time struggling to find a solution to a problem,
and ultimately convinces themselves, perhaps out of exhaustion,
that they have found the right solution.  But when someone new steps
into the room, that new person immediately recognizes the solution
for what it is -- a dog.  The group will generally try to pooh-pooh
the outsider's view, feeling that they just don't understand all
the complexities of the problem, or missed all the relevant discussions
that went on arriving at the solution, and if the group is unlucky,
they will ultimately dismiss the outsider's perspective.  I don't
think we can afford to do that.  We really want the changes to
Ada to stand the test of time, so years from now someone will
look at Ada 200Y as a whole and think that it is a good, well integrated,
internally consistent language, without a lot of ugly baggage
hanging off the side due to periodic "maintenance" activities.

Obviously, given our current resources, we don't want to waste
implementors' or users' time with enhancements that won't stand
the test of time, and have to be "re-maintained" many times
in the future to get them right.  There were a few dogs in
Ada 95 (like streams), and it has been painful to straighten
them out.  Luckily, for most of these dogs, the core idea
seems to have been good, even if the details were a shambles.

Anyway, so much for philosophizing...

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

From: Jean-Pierre Rosen
Sent: Thursday, January 30, 2003  10:06 AM

> Group think is where a relatively isolated group (e.g. the ARG)
> spends a very long time struggling to find a solution to a problem,
> and ultimately convinces themselves, perhaps out of exhaustion,
> that they have found the right solution.  But when someone new steps
> into the room, that new person immediately recognizes the solution
> for what it is -- a dog.  The group will generally try to pooh-pooh
> the outsider's view, feeling that they just don't understand all
> the complexities of the problem, or missed all the relevant discussions
> that went on arriving at the solution, and if the group is unlucky,
> they will ultimately dismiss the outsider's perspective.  I don't
> think we can afford to do that.  We really want the changes to
> Ada to stand the test of time, so years from now someone will
> look at Ada 200Y as a whole and think that it is a good, well integrated,
> internally consistent language, without a lot of ugly baggage
> hanging off the side due to periodic "maintenance" activities.
>
Are you thinking of unreserved keywords here?

(sorry, couldn't resist)

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

From: Randy Brukardt
Sent: Thursday, January 30, 2003   4:01 PM

Tucker said:

> ...  As a language designer/enhancer, I always want the new features to
look
> like they were "always" there, so the language is seamless and there is no
> obvious dividing line between old and new features.

That's clearly an impossible goal in this case, and using it as a criteria
is going to lead you nowhere.

The reason for that we're trying to do something unnatural to the basic
design of Ada: use something before it is declared. In order to do that, we
have to create some feature that allows using something that isn't even
declared yet. In order to make that implementable without major disruptions
(and that is a requirement politically, if not technically), it has to be
heavily restricted. But heavily restricting something is by itself
unnatural: usually, if you can declare something in one place, you can
declare it somewhere else as well (assuming appropriate visibility).

Moreover, any of solution of this sort requires making some subset of
"class" visible prematurely. And that, is, of itself, unnatural and
potentially error-prone. (At least Ada will check for problems at
compile-time, but its better to not have to do that in the first place.)

Any 'natural' solution would have to get rid of special cases and probably
eliminate most of the compilation order rules. But any such solution would
not be in the spirit of Ada.

To make the point clear, here is a quick look at every alternative offered
and why its unnatural (I'll do them in proposal order to avoid bias, and I'm
going to try to avoid any technical issues):
 1) With type. Unnatural because it's the only context clause item on
non-program units. Unnatural because its restricted to incomplete types
only. Why not private types or constants?
 2) Package abstracts. 3 package parts aren't enough apparently, so let's
add a fourth. Sheesh. This is a clear violation of the zero, one, or many
rule of good design. What goes in the extra part certainly isn't clear or
natural - you'd put whatever you had to in there to make the design work.
 3) Old type stubs (explicit completions). The idea of a stub is natural
enough, but limiting its use to very restricted cases isn't. The completion
syntax is new, but that hardly makes it unnatural. (Humm, I can't figure out
why this one would be unnatural. Too bad everyone hates it. I note that it
eliminates two of Tucker's concerns as well...)
 4) Current type stubs. As with the previous case, stubs are natural,
restricted cases aren't. The concern about having an undeclared dependency
remains. The limitation to the same name is unnatural, but is easily fixed.
 5) Type stubs with a context clause. It's unnatural to use something before
its declared, whether in the context clause or anywhere else. Otherwise, the
same as previous.
 6) Child package prefixes. These are unnatural because they're limited only
to the library level of library packages - no higher and no lower. And,
since they're just warmed over package abstracts, they have all of the
unnaturalness of that solution as well.
 7) Type C.T. This is the most unnatural of all. It has most of the faults
of both type stubs and package prefixes. First, we're declaring an expanded
name. This is new for non-program units. OK, but then why is it restricted
to just incomplete types? Why not deferred constants and by-reference
objects and private types ...? You're still forced to use these only at the
library level of library packages (otherwise it couldn't be a child),
greatly constraining the design. And you still have to figure out when they
need to be declared separately - and I expect that will occur only when its
clear that the design won't work any other way. Making people redo their
design because a need for mutual dependence arises is no better than making
them redo their existing code.

The real point is that it is not a language designer's job to decide how
programs ought to be designed, whether they're new, existing, or whatever.
It's the language's job to give the designers the tools to do that job. No
one on the ARG can say how Ada programs really are going to be designed
using these features -- at best, we can only guess. We shouldn't constrain
those designs unless we really have no choice. (And we shouldn't be saying
that people can't use "in out" parameters on functions or have a function
with no return statement, either. But that's a different story.) Type stubs
have the nice property that they can be used wherever they are needed: in
library specs, in private parts, in nested packages, even in a protected
entry body if the need arose. That gives maximum flexibility to the
designer.

Tucker's philosophy seems to be that 'new designs' should be sets of deeply
nested child packages. I've tried that design (with Claw), and was not very
pleased with the results. The primary problem is the package names get very
long. For me, as a use-adverse programmer that uses full dot notation on
everything except items declared in the local source text (and its spec,
with limits) [with very local use/use type clauses for sanity], the clutter
is awful. That's why CBuild was designed to be mostly flat. Similarly, the
temptation to use stuff from the parent's private part is strong, and
impossible to check for. Why allow that? (Of course, if you NEED it, then go
ahead.) So, for me, (mostly) flat is better. Your mileage may vary. But I
certainly do not want the language saying: "You have to use deeply nested
designs. You have to either use "use" clauses or (worse to my view) direct
visibility from source files that you don't even have open in your editor.
Or you have to junk all of your current programming tools to use a fancy
toolset that will let you find declarations in code that you haven't even
compiled yet (and won't compile, either)."

OK, enough philosophizing. (Gee, is there an echo in here??) :-)

>2) Type stubs are not necessarily "seen" by the type completer.

I suggested a possible fix for this yesterday. I do agree that that would be
a good idea, but it isn't necessary. The original type stub proposal (with
explicit completions) clearly does not have this problem (it has other
problems, of course).

> I think this could have negative implications for compilers
> like GNAT that have multiple representations for access types
> (access-to-unconstrained array can be thick or thin, and I
> presume there is no easy way to convert a thick pointer to a thin one).

This is an existing problem in Ada 95, as you can do this in a package spec.
deferred to a body. Whatever solution works there should work here. I
believe GNAT peeks, as you said, and it would have to do that for type
stubs.

> ...To be specific, we have said that to deal with cases where most types
have
> the same simple name (e.g. "Object"), you should use an idiom where a
separate
> package is created to hold the type stub.

There is not the slightest problem in fixing this problem; the ARG decided
NOT to fix this problem. That was a mistake then, and is still a mistake.
The type stub syntax ought to be something like:
    type T is separate of P.Object;
When I originally proposed this, I certainly had no intention on limiting
the names used, and I still think its an arbitrary restriction that causes
nothing but trouble. But I was out-voted in Cupertino. C'est la guerre.

> Type stubs have the unfortunate situation where the
> same type has two different fully expanded names.

What are you talking about? Every entity in Ada can have a multitude of
names. The names are completely irrelevant. To the extent that type stubs
talks about names, THAT is a problem. We're only interested in the entities
matching.

In Janus/Ada at least, there is no difference if the names are the same or
different. Every declaration makes a unique type slot, so incomplete types
and private types are different than the completing types. Whether or not
you're allowed to treat them as the same is handled by a bunch of complex
rules. And certainly, that would remain true in every proposal made here.

> We have to be focused on the person developing a new abstraction,
> and how the language can be enhanced in modest ways to
> enable that person to develop the abstraction without having
> to stand on their head.

Absolutely. And, in my opinion, forcing use of "unnecessary" child packages
is precisely that sort of standing on your head. If I redesigned CBuild from
scratch today, I still would use as few child packages as possible (see
above). Being forced to use a lot of them just to make Tucker happy makes no
sense to me at all.

Tucker, I know you believe that everything should be nested in several
layers of nearly empty packages. Fine, do your software any way you want.
Can we at least agree that not everyone agrees with your design structure?

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

From: Tucker Taft
Sent: Thursday, January 30, 2003   4:50 PM

Randy Brukardt wrote:
>
> Tucker said:
>
> > ...  As a language designer/enhancer, I always want the new features to look
> > like they were "always" there, so the language is seamless and there is no
> > obvious dividing line between old and new features.
>
> That's clearly an impossible goal in this case, and using it as a criteria
> is going to lead you nowhere.
>
> The reason for that we're trying to do something unnatural to the basic
> design of Ada: use something before it is declared.

But that is exactly what incomplete type declarations are for.
They are just too restrictive in scope.

In any case, Randy is right that one person's "natural" could be someone
else's "dog".  To me, extending the incomplete type declaration to
allow mutual dependence across child or nested packages is natural,
whereas to him it is an abomination.


> ...
> Tucker, I know you believe that everything should be nested in several
> layers of nearly empty packages. Fine, do your software any way you want.
> Can we at least agree that not everyone agrees with your design structure?

I think this is a bit of an exaggeration, but that is of course the
nature of these debates sometimes.  If we can't sway people with
our best technical arguments, we try emotional appeals (me too,
by the way ;-).

We may have to move toward the "Getting to Yes" approach of Camp David
if we can't come a little closer to consensus on this one.

What *can* we agree on, and thereby at least eliminate some of the
solutions from the table?  Once we get down to a small enough set
(hopefully two), we can ultimately just vote (much as I hate losing such votes ;-).

Possible points of consensus:

1) All inter-unit dependence must be either child on parent, body on spec,
or explicitly mentioned in some applicable context clause.

2) We need a mode of use that works reasonably with the "type Object" paradigm.

3) No new kinds of compilation units (is that still a point of consensus?)

Anything else in our consensus?  Are the above 3 in the consensus?

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

From: Randy Brukardt
Sent: Thursday, January 30, 2003   5:03 PM

Arnaud Charlet wrote:

> I don't think an automated tool that would take e.g. existing C or Java
> headers would be able to easily introduce an extra layer and put every
> needed circular dependence in the parent package. This would require a
> global processing of all possible units, and would mean having to
regenerate
> everything each time a new unit is added. It would also mean lots of
> unrelated declarations in the parent package.
>
> Unless I am missing something, this is definitely not a very attractive
> solution if you take the foreign language bindings into account.

This is a red herring. As I mentioned earlier, every solution considered
requires some sort of unnatural restructuring to use. That's just the nature
of the problem: we're trying to do something unnatural to the Ada model.

A binding generator simply has to assume that there might be circular
dependence (and might as well, given that these incomplete declarations
generate no code). That means generating whatever additional structure is
necessary to make this circular dependence possible.

For the particular proposal you are responding to, clearly every binding
would have a wrapper package that contained the incomplete type. A bit ugly
perhaps, but hardly a major problem. For type stubs, there would be a
separate "interface" package containing the incomplete type and an access
type to use everywhere. With type also needs such a separate type package
unless you never need a named access type (which seems unlikely given the
heavily pointered nature of those other languages). And for a package
prefix/abstract, you'd need the prefix. So there doesn't seem to be any
advantage to any of these proposals this way.

Obviously, you could "optimize" these extra artifacts away, but I think that
would be a bad idea, because, as you say, adding another class to the
program could change which ones are needed.

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

From: Randy Brukardt
Sent: Thursday, January 30, 2003   5:18 PM

Tucker was confused by my sentence:

> > We could get the advantages of (1) and not have the requirement to force
the
> > design, by requiring that the completion with the package containing the
> > stub.
>
> This sentence no verb. ;-)

And I couldn't parse it either when I replied. But it does have a verb:
"with", in the Ada sense. If I could write these messages in HTML, it would
have been in bold and would have made more sense:

We could get the advantages of (1) and not have the requirement to force the
design, by requiring that the completion WITH the package(s) containing the
stub.

I don't know if that makes it any clearer, but I hope so. Then we could
simplify the completion rules, because the stub would always be available if
the completion is. (There may be some simplification possible even without
this rule, but I think it would be more natural with it.) I'd pursue this
further, but I have a lot of other work I need to do before the meeting.

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

From: Dan Eilers
Sent: Thursday, January 30, 2003   6:04 PM

Tucker wrote:
> Anything else in our consensus?  Are the above 3 in the consensus?


I don't know if it rises to the level of consensus, but it seems highly
desirable from a usability point of view to require that clients of a
circular type not have to change on account of the circularity.

That means if there was previously a package Employees, with a type
Employee, and Employee was made circular with Departments.Department,
then clients could still "with" package Employees, and still refer to
type Employees.Employee.

Specifically, we can't require the client to use an invented
parent unit such as Directory.Employees.Employee, nor can we require
use of an invented child unit, such as Employees.Extension.Employee.
Nor do we want to require library-level renames to satisfy this
requirement.

Both the "with type" proposal and the "package abstracts" proposals
seem to meet this requirement, as does my proposal to put the "abstract"
in a child unit that can be compiled before its parent.  The early
type-stub proposal allowing the stubs in an unrelated package also
works.  But the modified type-stub proposal restricting the full type
to a child, as well as the package-prefix proposals both fail.

The difficulty seems to stem from the fact that child units are the
natural Ada way to extend a package, but the client should "with" the
main package, not an invented child containing the type completions.

A solution we haven't considered would be to allow a package spec to
be extendible via package subunits, which would contain the completions
of incomplete types in the package spec.  The subunits wouldn't be
"withable" by clients, but would be automatically included in any
"with" of the main package.  A different kind of "with" clause would
be used to "with" the main package without its subunits (i.e., the
abstract of the main package).  Something like "with employees'abstract".

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

From: Randy Brukardt
Sent: Thursday, January 30, 2003   6:13 PM

(BTW, sorry about answering some old messages a second time. I was filing
the mail, and some of the statements bothered me enough that I felt
compelled to reply -- not remembering that I did so yesterday. I think 44 is
too young to get Alzheimer's. :-)

Anyway,

Tucker wrote:
> But that is exactly what incomplete type declarations are for.
> They are just too restrictive in scope.
>
> In any case, Randy is right that one person's "natural" could be someone
> else's "dog".  To me, extending the incomplete type declaration to
> allow mutual dependence across child or nested packages is natural,
> whereas to him it is an abomination.

I'd agree with the premise, but the point is that that is exactly what type
stubs are supposed to be. Certainly, the original proposal with explicit
completion was designed that way precisely so that it was a natural
extension of the existing syntax and semantics. And that's still true with
the current one: it is just a different name (like a subtype) for the
completing type. You'll get all confused if you start paying attention to
exactly how that is accomplished. (That happens a lot in Ada; often, you're
better off not trying to understand the detailed rules unless you're an
implementor or language lawyer.) So I don't see any difference in the user
model for either of these proposals, only that type stubs isn't restricted
in how or where it can be used, and the Tucker "type C.T;" is restricted.

OTOH, it's a bit unnatural that this doesn't work for private types. More
generally, the problem is that Ada has several kinds of "restricted
visibility types", and really, that should have been a more general
mechanism, rather than a series of special kinds of types. Of course, its
too late to fix this in any useful way.

> > ...
> > Tucker, I know you believe that everything should be nested in several
> > layers of nearly empty packages. Fine, do your software any way you want.
> > Can we at least agree that not everyone agrees with your design structure?
>
> I think this is a bit of an exaggeration, but that is of course the
> nature of these debates sometimes.  If we can't sway people with
> our best technical arguments, we try emotional appeals (me too,
> by the way ;-).

The very first response you made to my original type stub proposal was
"...and I wouldn't mind requiring it to be a child of the package where the
incomplete type is declared,..." (July 9, 2001), so it seems to me that you
are always thinking in that direction. (How else could you stomach
restricting uses this way?) In any case, I was just trying to make sure that
you hadn't lost sight of all of the different ways Ada is used.

> ...
> What *can* we agree on, and thereby at least eliminate some of the
> solutions from the table?  Once we get down to a small enough set
> (hopefully two), we can ultimately just vote (much as I hate
> losing such votes ;-).

I fear that there is not much.

> Possible points of consensus:
>
> 1) All inter-unit dependence must be either child on parent, body on spec,
> or explicitly mentioned in some applicable context clause.

I can agree with this as written, because a type stub doesn't introduce
dependence. :-) So, from a language lawyer/implementor perspective, we're
fine.

But, clearly, there are some people who think that this
not-really-dependence needs to be in the context clause. Obviously, we need
to address their concern, but there is another alternative to agreeing with
this point: re-education. After all, Ada 83 didn't have the invisible child
on parent dependence, and it isn't clear from the context clause. Indeed, I
often forget that it exists, which is one reason that my personal coding
rules do not allow using the direct visibility on the parent to simplify
names. So, I don't see any horrible problem with adding another hidden
dependence, particularly when its not really a dependence at all (any change
to the completing package has no effect on the stub's package, so there is
no issue).

I really don't care either way, so if there is some strong support for this
position, I would be happy to go that way. (Which is why I prepared
alternative #5, so we could compare the wording changes needed with or
wothout such a context clause.)

> 2) We need a mode of use that works reasonably with the "type Object"
> paradigm.

I've always agreed with this. But I wonder if the whole ARG does, because we
voted down making type stubs do this. And I see no reason to require the
names to match: we don't do that for other sorts of renaming, why here?

> 3) No new kinds of compilation units (is that still a point
> of consensus?)

I'd rather not have any, but I must admit that it is the only way that I can
see to reconcile my viewpoints with yours. But I don't know if we can afford
to have new kinds of units.

> Anything else in our consensus?  Are the above 3 in the consensus?

Well, I think we should include:

0) We have to have a solution to mutually dependent types in the Amendment.
This is a very important problem which simply has to be solved (even if the
solution is ugly).

4) We have to be able to automatically translate headers from C++ or Java
into Ada using this feature.

I'd probably add, but don't know if it is a consensus point:

5) The model has to be reasonably easy to explain to the average experienced
Ada programmer.
(Because if we had done that the first time, we wouldn't be talking about it
now.)

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

From: Tucker Taft
Sent: Thursday, January 30, 2003   9:53 PM

Dan Eilers wrote:

> I don't know if it rises to the level of consensus, but it seems highly
> desirable from a usability point of view to require that clients of a
> circular type not have to change on account of the circularity.

For what its worth, thanks to library unit renaming, I don't see
any need for clients to change with the "type C.T;" approach.
For those situations where child packages just
won't do, you could use an approach like the following:

package Top is
    type Departments.Department;
    type Employees.Employee;
    ... -- any others needed to break circularity among
    ... -- top level packages
end Top;

package Top.Departments is
    type Department is ...

    procedure Add_Employee(Dpt : in out Department;
      Emp : access Employees.Employee);
    ...
end Top.Departments;

with Top.Departments;
package Departments renames Top.Departments;



package Top.Employees is
     type Employee is ...

     procedure Set_Manager(Emp : in out Employee;
       Mgr : access Managers.Manager);
     ...
end Top.Employees;

with Top.Employees;
package Employees renames Top.Employees;


Essentially, this is using "Top" as a package
where you can place the incomplete type declarations
for what are intended to be top-level library units,
if they are needed to break circularity.
[In this case we have placed both Departments.Department
and Employees.Employee into Top, but you could normally
get away with just one of them, since breaking
the circularity only requires one incomplete type declaration.]

It is then expected that all children of "Top"
will be renamed to be top-level library units
for use by clients.

If you generally design using package hierarchies,
then rarely will you have to use the "Top" trick.
E.g., both Departments and Employees might have
already been children of package Office, or Departments
might have been a child of Employees.

But in a pinch where you need mutual dependence
between packages that are not inside the same
package hierarchy, using a single "Top" parent
for all such packages would work.  It is almost
as though you were able to add incomplete type
declarations into the spec for Standard.

In fact, we could consider treating an explicit
declaration of a package Standard as meaning
"these are declarations to add at the end of my
package standard," but that would be incompatible
with all those folks out there who really do
have a library package called Standard (Standard.Standard,
that is).

I suppose compiling a file containing
only pragmas is similar to placing the pragmas in
package Standard, so this would be somewhat similar
to library-wide configuration pragmas.

Of course, you could also have a separate "Top"-like
package for each logical group of packages that
have a mutual dependence, but that begins to smell
like a package hierarchy again ;-).

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

From: Robert A. Duff
Sent: Friday, January 31, 2003  12:01 PM

Randy said:

> Well, I think we should include:
>
> 0) We have to have a solution to mutually dependent types in the Amendment.
> This is a very important problem which simply has to be solved...

Well said.

I would be perfectly happy with the original ARG-approved proposal that
WG9 rejected.  There were two concerns:

    - It seems bad to mention package names that aren't 'with'-ed.
      A perfectly legitimate response is: Yes, this is a legitimate
      point, but ARG is unable to fix the problem in the available time,
      and anyway, it's hardly a big deal.
      The other alternative is to add a new kind of with clause that
      does *not* introduce a dependency (in fact, it doesn't do much of
      anything except suppress a certain error message).  That's
      reasonable too, but I don't think we *have* to do that.

    - The "every type called Object" issue.  Well, it seems to me that
      when you choose this style, you are limiting yourself to one type
      per package (or at least one type called "Object" per package --
      presumably the "main" type).  So you need to create packages to
      hold all the type stubs.  So what?

Tucker doesn't like that proposal, for aesthetic reasons he has been
unable to articulate to *my* satisfaction.  Fine.  I'm also perfectly
willing to go along with Tucker's recent "type C.T;" proposal.  Tucker
has demonstrated that it is possible to add cycles without editing
clients, even in systems that do not currently use child units.  That
should address Dan's concern.  I also don't buy Randy's objections --
you don't need to introduce a whole bunch of child levels, you need to
introduce either zero or one.  And in the latter case, you can rename it
away as Tucker demonstrated.

Tucker's latest proposal does seem a bit simpler, and a bit easier to
implement.  And using incomplete types is a perfectly natural way to
address this issue.

Pascal, as our esteemed chair, please lock these folks in a room in
Padua, and don't let them out until they agree upon a solution.  ;-)

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

From: Dan Eilers
Sent: Friday, January 31, 2003  12:51 PM

Tucker wrote:
> For what its worth, thanks to library unit renaming, I don't see
> any need for clients to change with the "type C.T;" approach.

yes, that is workable, but looks to me like a "dog".  Ideally,
one class in other languages should be implementable with one
Ada package.  Two is a stretch, and the third (library renaming)
exceeds my threshhold of "dog".

I'd like to know if we really have a requirement to solve the
circular types problem for non-private types?

If we can limit ourselves to private types, and if we also intend
to solve the "private is separate" problem (which I hope we do),
then I think one simpler solution solves both problems (just like
circular types can be defined within a single package using private
types instead of incomplete types).

You would have some syntax, such as "private is separate" to say
the private part is separately compiled.  A normal "with" clause would
continue to cause a semantic dependence on both the public part and
the separately compiled private part.  A different kind of "with" clause,
such as "with p'abstract", would semantically depend on only the public
part.  This is what would be used at the top of the separately compiled
private parts to avoid'circular semantic dependencies.

This reduces the proposed 3-compilation-unit solution down to
just one compilation unit with a separately compiled private part.

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

From: Tucker Taft
Sent: Friday, January 31, 2003  8:28 PM

The problem is that the visible parts depend on one another,
not just the private parts.  They each have visible operations
that mention the other in formal parameters, presumably
via an access type.  This problem isn't solved by deferring
the private part, as far as I can see.

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

From: Tucker Taft
Sent: Friday, January 31, 2003  9:04 PM

Robert A Duff wrote:
 > ...
> Tucker doesn't like that proposal, for aesthetic reasons he has been
> unable to articulate to *my* satisfaction.

Yes I have aesthetic concerns, but I realize those are
not easily conveyed to others.  Basically, we have a totally
new construct that looks like nothing that appears anywhere
else in the language, and somewhat tortures the meaning
of "separate."

But my *non* "aesthetic" concerns (over and above
the two concerns expressed by SIGAda 2002 attendees) are
hopefully easier for others to understand, if
not agree with:

- it ends up creating two (or more) fully expanded names
   for the same type, with new, tricky-to-define-and-implement
   rules for when the names are equivalent;
- the recommended idiom of use seems to indicate that
   type stubs really belong in a "prefix" or "abstract"
   (or parent) part of the unit, not in some randomly named unit;
- the completing unit doesn't see the type stub, nor
   even know it exists, so it doesn't "know" it needs
   to match an access type representation that will be
   used by units that see only a stub.

[To address this third concern, Randy has
suggested requiring that the completing package
must "with" (all) the package(s) containing the stub(s).  This
seems difficult to enforce, since you seem to have recreated
the cyclic recompilation problem we were trying to eliminate.
I.e., when you add a new stub somewhere, you have to go and
check that the package referenced by the stub has a "with"
clause on it, but there is no requirement that the package
even exist, and in any case, it might be changed later.
So when you (re)compile the completing package, you must scan all units
in the system and see whether they now contain a stub.
This seems to be creating a mutual compilation dependence between
a unit containing a stub and the completing package,
which sounds painful.]

 > ...
> I'm also perfectly
> willing to go along with Tucker's recent "type C.T;" proposal....
 >
> Tucker's latest proposal does seem a bit simpler, and a bit easier to
> implement.  And using incomplete types is a perfectly natural way to
> address this issue.

Glad to hear that even if my aesthetic concerns about
type stubs are unconvincing, that the "type C.T" alternative
isn't dead on arrival as far as you are concerned...

> Pascal, as our esteemed chair, please lock these folks in a room in
> Padua, and don't let them out until they agree upon a solution.  ;-)

Sounds like fun.  I'll bring the Chianti... ;-) ;-)

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

From: Randy Brukardt
Sent: Friday, January 31, 2003  10:17 PM

> - it ends up creating two (or more) fully expanded names
>    for the same type, with new, tricky-to-define-and-implement
>    rules for when the names are equivalent;

The number of names is meaningless; it's how many types there are that
matters. The point about the complexity of matching the types is true, but I
think it's a self-inflicted problem.

...
> [To address this third concern, Randy has
> suggested requiring that the completing package
> must "with" (all) the package(s) containing the stub(s).  This
> seems difficult to enforce, since you seem to have recreated
> the cyclic recompilation problem we were trying to eliminate.

It's clearly a post-compilation check. That is, it's not enforced until the
partition is created. It doesn't have to be anything else, I think. (After
all, the existence of a child with the right name is essentially a post
compilation check, at least from the perspective of the stub.)

> I.e., when you add a new stub somewhere, you have to go and
> check that the package referenced by the stub has a "with"
> clause on it, but there is no requirement that the package
> even exist, and in any case, it might be changed later.
> So when you (re)compile the completing package, you must scan all units
> in the system and see whether they now contain a stub.
> This seems to be creating a mutual compilation dependence between
> a unit containing a stub and the completing package,
> which sounds painful.]

That's definitely not the model I had. My concern is simply that there be no
views of the completion that can't see (all) of the stubs for that
completion. (That's the main gain of your proposal, I think.)

...
> > Pascal, as our esteemed chair, please lock these folks in a room in
> > Padua, and don't let them out until they agree upon a solution.  ;-)
>
> Sounds like fun.  I'll bring the Chianti... ;-) ;-)

Better bring a lot... :-) :-) :-)

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

From: Robert A. Duff
Sent: Saturday, February  1, 2003  9:08 PM

No, not "dead on arrival" at all.  It is, perhaps, the simplest solution
proposed so far.  All I ask is that the Padua meeting come up with a
clear ARG-approved vote for *something* to send along to WG9.  Perhaps
with a strong admonishment not to nitpick, along the lines of Randy's
"We have to have a solution to mutually dependent types in the
Amendment."

In support of Tucker's proposal: All well-written Ada 95 programs have a
(mostly empty) parent package lying around.  The "type C.T" can always
be put there, without damaging clients.  In legacy Ada 83 programs, the
parent is Standard, and user's can't edit that.  But Tucker showed how
to use renaming tricks to get around that, still without damaging
clients.  Either way, there's never a need to totally restructure the
package hierarchy to introduce mutually-dependent types.

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

From: Tucker Taft
Sent: Friday, January 31, 2003  9:06 AM

One way to make progress might be to compare
attempts at actual wording for these various
proposals.  (I figure we don't have a shortage
of material for the AI "discussion" sections ;-).

Here is an attempt to provide wording
for the "incomplete child type" proposal.

[I have ignored the "is tagged" part
in the wording, because it is probably
time for us to separate tagged incomplete types out
into their own AI, as at this point they seem orthogonal
to our debate over the solution to the mutually dependent
packages problem.]

--------- proposed wording -------

Change paragraphs 3.10.1(2,3) as follows ("{}" are additions,
"[]" are deletions, except in the syntax part):

incomplete_type_declaration ::=
   TYPE {[package_identifier.]}defining_identifier[discriminant_part]
     {[is tagged]};

An incomplete_type_declaration requires a completion, which shall be
a full_type_declaration {, a private_type_declaration, or a
private_extension_declaration}.  {If a package_identifier
is present in the declaration, the completion shall occur immediately
within the visible part of a package with this identifier,
which shall be declared later and immediately within the innermost
enclosing declarative region.  Otherwise, if}[If] the
incomplete_type_declaration  occurs immediately within ...
    < rest remains the same >.

Add the following sentences to the end of paragraph 3.10.1(11):

If a package_identifier is present in the declaration, the
incomplete type is declared immediately within the declarative
region of the named package.  Otherwise, the incomplete type is
declared immediately within the innermost enclosing declarative region.

Change 8.3(19) as follows:

If the completion of a declaration is a declaration, then [within
the scope of] {in places where} the completion {is visible}, the
first declaration [is] {, and any declarations it completes, are}
hidden from all visibility.  Similarly, a discriminant_specification
or parameter_specification is hidden [within the scope of]
{in places where} a corresponding discriminant_specification
or parameter_specification of a corresponding completion, or
of a corresponding accept_statement {is visible}.

--------- end of wording ----------

This last part deserves some discussion.  The change from "within the
scope" to "places where visible" seems necessary for any of our
proposals, to avoid the "ripple" effect where an indirect "with"
dependence can have significant effects on a unit outside the
scope of the "with" clause.

The original "within scope" wording would pull completions
into all semantic dependents of the completing package, since the
scope of a library item extends to all its dependents, including
those units that do not have "with" visibility on the _item.  But
we have agreed in past discussions that we want the completing
package (or a rename thereof) to be visible, not just somewhere
within scope, if we are going to consider the type "completed."
The new wording of the paragraph is intended to have no effect
on existing code.

One note about the syntax, to address Randy's concern.  Adding the
optional "[package_identifer.]" to the syntax could be treated by the
parser roughly in the same way as the optional "[parent_unit_name.]"
is treated in section 6.1 for defining_unit_name.  You could allow
this prefix on any type declaration, and then have a semantic
rule that makes sure it is only used for incomplete type
declarations.

My belief is that this proposal will have the simplest wording
and implementation effort, and with the use of the "Top" package
approach I mentioned in an earlier message, can accommodate use of
the feature for packages that are not part of a package
hierarchy.

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

From: Robert Dewar
Sent: Saturday, February  1, 2003  9:18 PM

> In support of Tucker's proposal: All well-written Ada 95 programs have a
> (mostly empty) parent package lying around.  The "type C.T" can always
> be put there, without damaging clients.  In legacy Ada 83 programs, the
> parent is Standard, and user's can't edit that.  But Tucker showed how
> to use renaming tricks to get around that, still without damaging
> clients.  Either way, there's never a need to totally restructure the
> package hierarchy to introduce mutually-dependent types.


I disagree with this claim. You can't just make a style statement like
that without some real evidence of consensus. I see none. OK, so Bob
Duff says

a) almost all existing Ada 95 programs are badly written

b) we don't care about programs that are badly written

c) our proposal is only for well written programs

This is not the way to get a proposal approved. I very much doubt that WG9
can be persuaded by an argument that says:

a) we have a solution to the mutual types problem
b) it's not really right, and we are not happy with it
c) but we have to have something, so you should approve it anyway.

The concentration must remain on getting a solution that has real
consensus technically at the ARG and grass roots level, and only
then does it make sense to take something to WG9.

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

From: Randy Brukardt
Sent: Saturday, February  1, 2003  9:36 PM

Bob said:

> In support of Tucker's proposal: All well-written Ada 95
> programs have a (mostly empty) parent package lying around.

Oh-oh. Those are fighting words, 'cause they imply that every line of Ada 95
code that's I've ever written is not "well-written Ada 95". There is no such
package in Claw, or CBuild, or AdaServe, or anything else I've written.

That's due, in large part, to the fact that I care about the names of things
for the use-adverse. The names in Claw are too long the way it is, adding
another level just to meet someone's idea of good style is ridiculous.

Saying that you can use "renaming tricks" is fine, but my style is to use
those only for compatibility with legacy code. In new code, I always use the
full name. Case in point, I always use Ada.Text_IO, never Text_IO. An extra
level of packages means that the names are even harder to read and write. So
I use them only when it is necessary to the design.

Having the language enforce someone's idea of good style (especially one not
shared by many of us!) is a very bad idea.

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

From: Robert A. Duff
Sent: Saturday, February  1, 2003 10:01 PM

> > In support of Tucker's proposal: All well-written Ada 95 programs have a
> > (mostly empty) parent package lying around.  The "type C.T" can always
> > be put there, without damaging clients.  In legacy Ada 83 programs, the
> > parent is Standard, and user's can't edit that.  But Tucker showed how
> > to use renaming tricks to get around that, still without damaging
> > clients.  Either way, there's never a need to totally restructure the
> > package hierarchy to introduce mutually-dependent types.
>
> I disagree with this claim.

OK, let me state it differently:

There are two cases: you have a parent lying around (that's the style I
usually like) or you don't.  If you do, there's a clear place to put the
incomplete type (in the parent of wherever the type already is).  If you
don't, the renaming tricks work seemlessly.  Either way, there's no
problem for clients.

>...You can't just make a style statement like
> that without some real evidence of consensus. I see none. OK, so Bob
> Duff says
>
> a) almost all existing Ada 95 programs are badly written

OK, I back off on that.

> b) we don't care about programs that are badly written

I never said that.  I explicitly pointed out that those programs can
easily deal with it.  (I admit "badly written" was a poorly chosen value
judgement.)  My point was that there's no problem for those programs
that choose that flat-namespace style.

> c) our proposal is only for well written programs

Not at all.  Please read my comment again: you'll see that the proposal
works fine for both styles, which is the goal.  Note my claim, "Either
way, there's never a need to totally restructure the package hierarchy
to introduce mutually-dependent types."

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

From: Robert A. Duff
Sent: Saturday, February  1, 2003 10:12 PM

Randy said:

> Bob said:
>
> > In support of Tucker's proposal: All well-written Ada 95
> > programs have a (mostly empty) parent package lying around.
>
> Oh-oh. Those are fighting words,

I didn't *mean* them to be "fighting words".  ;-)

>... 'cause they imply that every line of Ada 95
> code that's I've ever written is not "well-written Ada 95". There is no such
> package in Claw, or CBuild, or AdaServe, or anything else I've written.

Heh?  I thought everthing was under a parent CLAW or CBuild or whatever.

The point is that if you happen to have a parent already, that's a
reasonable place for the incomplete type decl.  No big deal.  If you
don't, it's *still* no big deal because of package renamings.

...
> Having the language enforce someone's idea of good style (especially one not
> shared by many of us!) is a very bad idea.

I completely agree -- no enforcing of style is intended here.

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

From: Randy Brukardt
Sent: Saturday, February  1, 2003  9:56 PM

I just looked at the implementation implications of Tucker's "type C.T"
proposal in Janus/Ada.

Janus/Ada is a syntax-directed compiler in the classic style (as it started
as an class project, and the textbook was the dragon book). That means a
syntax change (as opposed to addition) can have ripple effects throughout
the compiler.

The syntax that the compiler uses for incomplete types is currently:
    Type_Head discrim_option SEMICOLON
where Type_Head is
    TYPE IDENTIFIER

In order to implement Tucker's syntax, we'd have to change Type_Head to:
    TYPE IDENTIFIER DOT IDENTIFIER |
    TYPE IDENTIFIER

Type_Head is used in all type declarations, including generic formal types.
(There is a comment which says that the grammar is not LALR(1) if that is
not done).

The processing done for Type_Head is to enter an empty, dummy type into the
symbol table. Discrim_Option "knows" where this is, and puts the
discriminants into that type.

This means that this change would have two major impacts on the compiler:
    All types (including formal types) would have to be able to do
declarations into these "ghost" packages. An error would be generated, of
course, but we can't stop processing the program for such a trivial
appearing error. And we have to do something sensible (not crash!) in any
case, even though the program is illegal. A large part of the bugs that we
have to fix are errors in error handling. This is on top of the semantic
check itself.
    The declarations of discriminants would have to be rewritten to support
insertion into a ghost package rather than the current declaration location.
It might be possible to "fool" this code into writing into a ghost package,
but then that would have to be undone at every possible type declaration.

In summary, this looks like a bigger change than type stubs.

Indeed, if my proposed simplification to the completion rules was adopted, I
don't believe that any change to type matching or to type declarations or
use would be needed. The only real change (besides actually implementing the
declaration) would be to context clause processing to "hook" the stub to the
completion (which is necessary in Tucker's proposal as well as original type
stubs).

BTW, I mentioned yesterday that a post-compilation rule was necessary to
make that idea work. That's not actually true (although it might still be a
good idea to have one). The only impact if the completion did not with the
package containing the stub would be that the completion would never match
the stub (no matter what was withed elsewhere). That seems tolerable to me,
but since it would probably cause mysterious errors, a post-compilation
check is better. Note that the post-compilation check would have to not be
triggered if there was no completion at all.

I'll try to write up the wording for this, but probably not until I'm on my
way to the meeting.

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

From: Tucker Taft
Sent: Monday, February 3, 2003  1:55 PM

Randy Brukardt wrote:
>
> I just looked at the implementation implications of Tucker's "type C.T"
> proposal in Janus/Ada.
>
> Janus/Ada is a syntax-directed compiler in the classic style (as it started
> as an class project, and the textbook was the dragon book). That means a
> syntax change (as opposed to addition) can have ripple effects throughout
> the compiler.

I sympathize here.  Our compiler does essentially all semantic analysis on
the fly while parsing.  We don't build up syntax trees for anything
much bigger than an expression, and we do the first "pass" of overload
resolution while building up expression trees.

> The syntax that the compiler uses for incomplete types is currently:
>     Type_Head discrim_option SEMICOLON
> where Type_Head is
>     TYPE IDENTIFIER
>
> In order to implement Tucker's syntax, we'd have to change Type_Head to:
>     TYPE IDENTIFIER DOT IDENTIFIER |
>     TYPE IDENTIFIER
>
> Type_Head is used in all type declarations, including generic formal types.
> (There is a comment which says that the grammar is not LALR(1) if that is
> not done).

I presume that is not the only place where the grammar is not LALR(1)!

> The processing done for Type_Head is to enter an empty, dummy type into the
> symbol table. Discrim_Option "knows" where this is, and puts the
> discriminants into that type.
>
> This means that this change would have two major impacts on the compiler:
>     All types (including formal types) would have to be able to do
> declarations into these "ghost" packages. An error would be generated, of
> course, but we can't stop processing the program for such a trivial
> appearing error. And we have to do something sensible (not crash!) in any
> case, even though the program is illegal. A large part of the bugs that we
> have to fix are errors in error handling. This is on top of the semantic
> check itself.
>     The declarations of discriminants would have to be rewritten to support
> insertion into a ghost package rather than the current declaration location.
> It might be possible to "fool" this code into writing into a ghost package,
> but then that would have to be undone at every possible type declaration.

Would you really need to undo anything?  It seems that you would simply allow
any sort of type in a "ghost" package, but of course give some kind
of error message if it turns out not to be incomplete, because that is
the "arbitrary" restriction that the silly ARG imposed.  You would
then also be ready for future enhancements to the language ;-).

> In summary, this looks like a bigger change than type stubs.

It is of course impossible for anyone outside RR to evaluate that,
but I can say that for our compiler, dealing with the "availability"
rules associated with type stubs was looking like a brand new kettle of fish.

> ...
> BTW, I mentioned yesterday that a post-compilation rule was necessary to
> make that idea work. That's not actually true (although it might still be a
> good idea to have one). The only impact if the completion did not with the
> package containing the stub would be that the completion would never match
> the stub (no matter what was withed elsewhere). That seems tolerable to me,
> but since it would probably cause mysterious errors, a post-compilation
> check is better. Note that the post-compilation check would have to not be
> triggered if there was no completion at all.

It would seem that if you go this far, then you should only allow one stub
in the program.  Allowing multiple stubs seems like gratuitous complexity
in the matching rules.  Was it your intent to allow only one stub,
and require that the stub be visible (due to "withing" the enclosing
package or a renaming thereof) at the point of the completing type declaration?

> I'll try to write up the wording for this, but probably not until I'm on my
> way to the meeting.

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

From: Pascal Leroy
Sent: Monday, February  3, 2003  4:20 AM

> There seems to be some feeling that type stubs
> were almost right, and we should either leave
> them as is, or add some kind of special context
> clause such as "separate with ..." and be done with it.

I am one of the people who thought that type stubs were "almost right" and I
must admit that I am getting more and more uncomfortable with this proposal.  I
think that your "philosophizing" nicely summarizes the issues, and I only
wished you wrote it earlier (it's only a few days before the meeting...).

> 1) Type stubs look and feel like an add-on to the language.

Agreed, but then so do your latest proposals regarding package prefixes and
"type C.T".  Other than shuffling the keywords around, I don't see that they
integrate much better in the existing language.  Actually, other that package
abstracts, all the proposals look like warts.

> 2) Type stubs are not necessarily "seen" by the type completer.

You're right, this might be a serious implementation problem, although not
necessarily more complicated than having three-part types or a new kind of
compilation unit.

> 3) Type stubs seems to require a particular "idiom" of use
>     that makes it seem clear that some kind of package "prefix"
>     or "abstract" is what we *really* wanted but couldn't somehow
>     bring ourselves to provide.

Yes, it's always suspicious when we have to recommend a particular idiom to
achieve some effect that should be straightforwardly supported by the language.
See for instance the idioms to "simulate" multiple inheritance or downward
closures in Ada 95.

> 4) Type stubs have the unfortunate situation where the
>     same type has two different fully expanded names.

I cannot get too excited about this problem.  At the implementation level you
have to match up distinct type declarations, whatever the model, so it doesn't
bother me too much that they have distinct expanded names.

> b) package prefix/abstract feels like a big change, requiring a new
>     kind of program unit, a new kind of context clause, and non
>     obvious rules about what part of the parent unit a child
>     prefix/abstract can see.  Admittedly, the package prefix is
>     probably the most powerful and flexible.

I think that package abstract is in some sense the most logical choice, and
that it's the approach we would choose if the year were 1980 and we were not
concerned about disrupting implementations.

> c) "type C.T;" seems like a natural outgrowth of two basic facts:
>      i) the incomplete type declaration is the fundamental way
>         of supporting mutually dependent types in Ada, but it
>         is limited to only working within a single package spec;
>      ii) child packages are the fundamental way of splitting a large
>         abstraction into smaller, more manageable parts, but they are
>         limited in that mutually dependent types cannot cross
>         these pieces of the abstraction.

I am sorry, I don't see the connection.  Both (i) and (ii) are true statements,
but I don't understand why you absolutely want to tie a solution to the problem
of mutually-dependent types to child units.  To me this fails your criteria #1
above, and using child units for that purpose looks totally awkward.

> The major objection to
> the more flexible incomplete type declaration seems to be that
> it might not just "drop" into existing code.

As far as I am concerned there is also an aesthetical reason, which I find hard
to convey, but I feel strongly about it: child units are not the proper
construct to solve the problem at hand.

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

From: Tucker Taft
Sent: Monday, February 3, 2003  2:35 PM

Pascal Leroy wrote:
> ...
> > c) "type C.T;" seems like a natural outgrowth of two basic facts:
> >      i) the incomplete type declaration is the fundamental way
> >         of supporting mutually dependent types in Ada, but it
> >         is limited to only working within a single package spec;
> >      ii) child packages are the fundamental way of splitting a large
> >         abstraction into smaller, more manageable parts, but they are
> >         limited in that mutually dependent types cannot cross
> >         these pieces of the abstraction.
>
> I am sorry, I don't see the connection.  Both (i) and (ii) are true statements,
> but I don't understand why you absolutely want to tie a solution to the problem
> of mutually-dependent types to child units.  To me this fails your criteria #1
> above, and using child units for that purpose looks totally awkward.

In my personal view of the world, if two types are mutually dependent,
they are in some sense part of the "same" abstraction,
or at least parts of two closely related abstractions.
And in this same world view, all parts of a single abstraction should be grouped
together within a single part of the program's namespace.

Ada 95 pushes the programmer this way since generally
parts of the same abstraction all need visibility
on some common bit of hidden information, such as a private
part of some package.  We considered the (dreaded) "with private"
approach to "opening up the Kimono" of a private type,
and rejected it in the Ada 9X process.  We concluded
that there were many advantages to keeping visibility
on hidden information within a well defined part of the namespace.

This is the reason I see support for mutual dependence
only between packages in the same package hierarchy as
a perfectly acceptable limitation.  Combined with the
ability to hide this package hierarchy using renaming,
in the situations where it is undesirable to tie
these packages together in the namespace, it seemed like
a good, simple (even elegant? ;-) solution to the problem.

> > The major objection to
> > the more flexible incomplete type declaration seems to be that
> > it might not just "drop" into existing code.
>
> As far as I am concerned there is also an aesthetical reason, which I find hard
> to convey, but I feel strongly about it: child units are not the proper
> construct to solve the problem at hand.

Unfortunately, design issues often depend on our intuitions
about what makes sense and what doesn't.  Sometimes our
intuitions line up, and sometimes they don't.  With this
one, we aren't doing a lot of lining up ;-(.

I think we also are being reminded why design by committee is so hard,
if the entire committee is committed to producing an excellent,
intuitively obvious, elegant, aesthetic, implementable design.

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

From: Randy Brukardt
Sent: Monday, February 3, 2003  8:16 PM

Tucker replied to me:

> > Type_Head is used in all type declarations, including generic formal types.
> > (There is a comment which says that the grammar is not LALR(1) if that is
> > not done).
>
> I presume that is not the only place where the grammar is not LALR(1)!

Our grammar is LALR(1) of course; the comment just was there to tell me not
to bother trying to separate these cases, because it won't work. I know that
otherwise, I'd try to "improve" the grammar to eliminate these useless
cases, and waste a lot of time.

There is no obvious relationship between our compiler's grammar and the one
in the RM. (For the obvious reasons).

> >     The declarations of discriminants would have to be rewritten to support
> > insertion into a ghost package rather than the current declaration location.
> > It might be possible to "fool" this code into writing into a ghost package,
> > but then that would have to be undone at every possible type declaration.
>
> Would you really need to undo anything?  It seems that you would simply allow
> any sort of type in a "ghost" package, but of course give some kind
> of error message if it turns out not to be incomplete, because that is
> the "arbitrary" restriction that the silly ARG imposed.  You would
> then also be ready for future enhancements to the language ;-).

You'd have to "undo" declaring into the ghost package, because if you
didn't, everything declared after it would go into the ghost. That would be
bad, even for an illegal program, because it would cause cascading errors.
And that would have to be done in every kind of type declaration.

> > In summary, this looks like a bigger change than type stubs.
>
> It is of course impossible for anyone outside RR to evaluate that,
> but I can say that for our compiler, dealing with the "availability"
> rules associated with type stubs was looking like a brand new
> kettle of fish.

With the simplified rules you and I have been discussing, I believe that
type stubs (not including tagged incomplete) would take 4 hours of work.
Period. One mildly messy routine to run at the end of context clause
processing (to look for completions of any stubs loaded), and one rather
simple post-compilation check. Nothing for "availablility" at all, it
follows from standard type matching and visibility. It'll take longer to
figure out where the routines go than to write and test them.

> > ...
> > BTW, I mentioned yesterday that a post-compilation rule was necessary to
> > make that idea work. That's not actually true (although it might still be a
> > good idea to have one). The only impact if the completion did not with the
> > package containing the stub would be that the completion would never match
> > the stub (no matter what was withed elsewhere). That seems tolerable to me,
> > but since it would probably cause mysterious errors, a post-compilation
> > check is better. Note that the post-compilation check would have to not be
> > triggered if there was no completion at all.
>
> It would seem that if you go this far, then you should only allow one stub
> in the program.  Allowing multiple stubs seems like gratuitous complexity
> in the matching rules.  Was it your intent to allow only one stub,
> and require that the stub be visible (due to "withing" the enclosing
> package or a renaming thereof) at the point of the completing
> type declaration?

Not on Saturday. Thinking about that yesterday and this morning, I concluded
that it would be better to restrict to one stub per type (otherwise, you
have the stub-stub matching rules, or they don't match, which is weird). It
isn't critical, but it would avoid surprises.

Anyway, this idea may be OBE. Since I thought that your proposal was too
much work to implement, Pascal decided to propose one that would be ten
times more work. :-)

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

From: Randy Brukardt
Sent: Friday, March 21, 2003  10:40 PM


Here is an updated type stubs AI. What's new is essentially what was
discussed at Padua:

-- The context clause has been changed to "limited with". I looked for other
syntax, but this seems the best. I considered using less-preferable syntax
in order to avoid confusion with other proposals, but that seems to be a
mistake. After all, soon there will be only one proposal, and that proposal
should use the best possible syntax.

-- There are two new post-compilation rules. The first is simply that the
unit named in a "limited with" is needed in the partition. That's necessary
so that the other rules can be enforced. The second is that the unit which
has a "limited with" clause in its context_clause must be in the semantic
closure of the unit named in the "limited with" clause. This rule insures
that the completing type "knows" about any type_stubs that it has. This
means that all checking of the legality of a completion can occur when the
unit containing the completion is compiled. In addition, the implementation
can know that incomplete types of the type exist, and adjust its choice of
representations accordingly (that was considered important in Padua).

-- Only a single stub is allowed for each incomplete type. (This eliminates
the need to
match different stubs, and was considered important in Padua. Given the
"incomplete view" model that I've adopted, there is no longer any wording
needed for this case at all, but the restriction has been retained as it may
simplify implementations. This is dicussed in the !discussion section of the
AI.)

-- The full type name is specified in the type stub, thus allowing the name
to be changed if necessary (this provides a direct solution to the "Object"
problem).

-- I defined "incomplete view" and "complete view", and avoided futzing with
the visibility rules at all. The basic rule is that if the complete view is
available, it is used instead of the incomplete view. See the AI for
details.

-- I didn't try to allow local and nested completion of type stubs. That's
relatively easy to do, but it makes the wording complicated in a couple of
places. If we went further and allowed completion in private parts and
bodies (presumably subject to some restrictions), then an existing
incomplete types would be just a shorthand for a type stub.

I'll now go and try to relax before the inevitable barrage of problems...

[Editor's note: This is version /02 of the AI.]

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

From: Randy Brukardt
Sent: Friday, March 21, 2003  11:48 PM

I've refreshed this example I've used in the past. I'll send versions using
alternative #6 and #7 momentarily.

----

This example shows two ways that I would use alternative #5 of AI-217
in the Claw Builder.

The Claw Builder is a real, existing program which could use this facility.
The problem is that some objects need references to other types of objects,
and these needs are circular. For instance, (some) types of window objects
include menu objects. And some types of menu objects include actions that
open a window.

The current Claw Builder solves this problem by using names rather than
access objects to connect the objects in some cases. This is usually done
only where necessary to break circularities. For instance, menu objects name
the windows they are to open, rather than linking to them. Using names
causes several problems:
   -- Accesses to the linked object is much slower, as they have to be
      looked up by name before use;
   -- If the user renames the linked object, we have to walk the entire
      project to insure any names are updated;
   -- If the user copies the linked object and then renames the copy (the
      required behavior), we have to be careful NOT to walk the project
      and update names -- harming code reuse.
   -- We can't have overloaded names (not a problem for windows, but can
      happen in other cases).

A root window object is an abstract object with a fairly large set of
operations. Each concrete object has to provide implementations for many of
these operations (some it can inherit). All of these operations are
dispatching. Typically, a user of the operation would apply it to a list of
windows using an iterator generic, with the operation dispatching to the
correct implementation. For the purposes of this discussion, we'll look at
just a few: Show, Hide, Display_Name.

The existing package looks something like:

   with CBuild_Menu;
   package CBuild_Root is
      type Root_Window_Type is abstract new
	    Ada.Finalization.Limited_Controlled with private;
      type Any_Window_Access_Type is access all Root_Window_Type'Class;

      procedure Show (Window : in out Root_Window_Type) is abstract;
      procedure Hide (Window : in out Root_Window_Type) is abstract;
      function Display_Name (Window : in Root_Window_Type)
          return String is abstract;
      ...
   private
      type Root_Window_Type is abstract new
	    Ada.Finalization.Limited_Controlled with record
          ... CBuild_Menu.Something ...
      end record;
   end CBuild_Root;

The menu package looks something like (greatly simplified):

  with CBuild_Id_Type;
  package CBuild_Menu is
    type Menu_Item is record
       Name : String (1..20);
       Action : Action_Type;
       Dialog : CBuild_Id_Type; -- The name of a dialog window.
           -- If Action=Open_Dialog.
    end record;
    procedure Simulate_Action (Item : in Menu_Item);
  end CBuild_Menu;

  with CBuild_Root, CBuild_Lists;
  package body CBuild_Menu is
    procedure Simulate_Action (Item : in Menu_Item) is
    begin
       if Item.Action = No_Action then
           null;
       elsif Item.Action = Open_Dialog then
           CBuild_Root.Show (
                 CBuild_Lists.Lookup(Item.Dialog,
                     CBuild_Data.Top_Level_Window_List));
       ... -- Other actions.
       end if;
    end Simulate_Action;
  end CBuild_Menu;


In order to directly use a Any_Window_Access_Type instead of the name in
CBuild_Menu, we would need restructure the CBuild_Root package. We'd need to
construct an abstract of this package for use in circular definitions.
(Caveat, I haven't actually done this, not having a compiler with this
feature.) Using alternative #5 (and assuming that AI-326 is approved), this
could look like:

   limited with CBuild_Root;
   package CBuild_Root_Abstract is
      type Root_Window_Type is tagged
          separate of CBuild_Root.Root_Window_Type;
      type Any_Window_Access_Type is access all Root_Window_Type'Class;
   end CBuild_Root_Abstract;

This abstract would be used only when you need to declare instances (usually
components) of the type in locations where the reference would be circular.

In order to keep the access types compatible, the real package would be
modified to:

   with CBuild_Root_Abstract; -- Note: Required by alternative #5/02
   with CBuild_Menu;
   package CBuild_Root is
      type Root_Window_Type is abstract new
	    Ada.Finalization.Limited_Controlled with private;
      subtype Any_Window_Access_Type is
CBuild_Root_Abstract.Any_Window_Access_Type;

      procedure Show (Window : in out Root_Window_Type) is abstract;
      procedure Hide (Window : in out Root_Window_Type) is abstract;
      function Display_Name (Window : in Root_Window_Type)
          return String is abstract;
      ...
   private
      type Root_Window_Type is abstract new
	    Ada.Finalization.Limited_Controlled with record
          ... CBuild_Menu.Something ...
      end record;
   end CBuild_Root;

The client package (in this case, for menus) would look something like:

  with CBuild_Root_Abstract;
  package CBuild_Menu is
    type Menu_Item is record
       Name : String (1..20);
       Action : Action_Type;
       Dialog : CBuild_Root_Abstract.Any_Window_Access_Type;
           -- If Action=Open_Dialog.
    end record;
    procedure Simulate_Action (Item : in Menu_Item);
  end CBuild_Menu;

  with CBuild_Root;
  package body CBuild_Menu is
    procedure Simulate_Action (Item : in Menu_Item) is
    begin
       if Item.Action = No_Action then
           null;
       elsif Item.Action = Open_Dialog then
           CBuild_Root.Show (Item.Dialog.all);
       ... -- Other actions.
       end if;
    end Simulate_Action;
  end CBuild_Menu;

I don't much like this solution, because it's not clear when to use the
abstract package, and when to use the main package. It would be preferable
to keep an understandable separation between them.

One way to do this is create a "client" package and a "creator" package. The
"client" package  would be used by ordinary client packages of the
abstraction. The "creator" package would be used only by packages that need
to create new extensions of the type or create objects of the type. The
"creator" package would, of course, be similar to the existing package. The
"client" package would provide enough operations that regular clients could
use it only.

Since the "client" package would be used most frequently, I've given it the
existing name.

   limited with CBuild_Root_Definition;
   package CBuild_Root is
      type Root_Window_Type is tagged separate of
          CBuild_Root_Definition.Root_Window_Type;
      type Any_Window_Access_Type is access all Root_Window_Type'Class;

      procedure Show (Window : in out Root_Window_Type'Class);
      procedure Hide (Window : in out Root_Window_Type'Class);
      function Display_Name (Window : in Root_Window_Type'Class)
          return String;
      ...
   end CBuild_Root;

The "creator" package would be as in the previous example (except for the
name):

   with CBuild_Root; -- Note: Required by alternative #5/02
   with CBuild_Menu;
   package CBuild_Root_Definition is
      type Root_Window_Type is abstract new
	    Ada.Finalization.Limited_Controlled with private;
      subtype Any_Window_Access_Type is
CBuild_Root_Abstract.Any_Window_Access_Type;

      procedure Show (Window : in out Root_Window_Type) is abstract;
      procedure Hide (Window : in out Root_Window_Type) is abstract;
      function Display_Name (Window : in Root_Window_Type)
          return String is abstract;
      ...
   private
      type Root_Window_Type is abstract new
	    Ada.Finalization.Limited_Controlled with record
          ... CBuild_Menu.Something ...
      end record;
   end CBuild_Root_Definition;

The body of CBuild_Root would need visibility on the completing type so that
it
could implement the procedures:

   with CBuild_Root_Definition;
   package body CBuild_Root is
      procedure Show (Window : in out Root_Window_Type'Class) is
      begin
          CBuild_Root_Definition.Show (Window);
      end Show;
      procedure Hide (Window : in out Root_Window_Type'Class) is
      begin
          CBuild_Root_Definition.Hide (Window);
      end Hide;
      function Display_Name (Window : in Root_Window_Type'Class)
          return String is
      begin
          return CBuild_Root_Definition.Display_Name (Window);
      end Display_Name;
      ...
   end CBuild_Root;

With this structure, the clients with CBuild_Root, and the concrete object
packages with (or are children of) CBuild_Root_Definition. The two packages
have clearly defined roles.

For instance, the menu case would look something like:

  with CBuild_Root;
  package CBuild_Menu is
    type Menu_Item is record
       Name : String (1..20);
       Action : Action_Type;
       Dialog : CBuild_Root.Any_Window_Access_Type;
            -- If Action=Open_Dialog.
    end record;
    procedure Simulate_Action (Item : in Menu_Item);
  end CBuild_Menu;

  package body CBuild_Menu is
    procedure Simulate_Action (Item : in Menu_Item) is
    begin
       if Item.Action = No_Action then
           null;
       elsif Item.Action = Open_Dialog then
           CBuild_Root.Show (Item.Dialog.all);
       ... -- Other actions.
       end if;
    end Simulate_Action;
  end CBuild_Menu;

The dereference in the call to Show is allowed, by the second bulleted rule
under when a dereference is allowed. This is OK and can be implemented
because we don't need to know anything at all about the real type in order
to generate the call. Such a call cannot be dispatching (the only way to see
a primitive operation is for the completion to be "available"). Thus, it
cannot be using a tag. And we know the parameter passing mode (by
reference), and we know that the body (or at least some body) must be in the
scope of the
completion, or nothing at all must be done with the type.

---

Of course, the best way to avoid the issue of deciding when to use one of
the two packages is to avoid having the second one in the first place. The
primary reason we need this package is because of access type proliferation
problems. If the solution in AI-230 is adopted, we don't have that problem.
In that case, we can put the stub directly in the menus package.

In that case, the CBuild_Root package need not be modified at all:

   with CBuild_Menu;
   package CBuild_Root is
      type Root_Window_Type is abstract new
	    Ada.Finalization.Limited_Controlled with private;
      type Any_Window_Access_Type is access all Root_Window_Type'Class;

      procedure Show (Window : in out Root_Window_Type) is abstract;
      procedure Hide (Window : in out Root_Window_Type) is abstract;
      function Display_Name (Window : in Root_Window_Type)
          return String is abstract;
      ...
   private
      type Root_Window_Type is abstract new
	    Ada.Finalization.Limited_Controlled with record
          ... CBuild_Menu.Something ...
      end record;
   end CBuild_Root;

Then, the menu package would declare the stub and an anonymous access type:

  limited with CBuild_Root;
  package CBuild_Menu is
    type Root_Window_Type is
       tagged separate of CBuild_Root.Root_Window_Type;
    type Menu_Item is record
       Name : String (1..20);
       Action : Action_Type;
       Dialog : access Root_Window_Type'Class;
           -- If Action=Open_Dialog.
    end record;
    procedure Simulate_Action (Item : in Menu_Item);
  end CBuild_Menu;

  with CBuild_Root;
  package body CBuild_Menu is
    procedure Simulate_Action (Item : in Menu_Item) is
    begin
       if Item.Action = No_Action then
           null;
       elsif Item.Action = Open_Dialog then
           CBuild_Root.Show (Item.Dialog.all);
       ... -- Other actions.
       end if;
    end Simulate_Action;
  end CBuild_Menu;

This solution clearly perturbs the existing program the least, so it is
preferred if it is available.

However, this solution runs afoul of the only one stub rule. If there is
more than one package that needs a stub, we're forced to switch back to one
of the other structures. Since that rule buys a bit of implementation
simplification and not much else (it has no effect on the wording
currently), it may make sense to drop it.

Another issue is the requirement that the package containing the completing
type have semantic dependence on the stub-containing package. In some cases,
that will reintroduce the circularity that we're trying to eliminate. In
those cases, two packages are required.

That concludes my look at using alternative #5/02 in CBuild. Coming soon: a
similar look at alternative #7.

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

From: Randy Brukardt
Sent: Wednesday, March 19, 2003 10:17 PM

I'm trying to get a handle on the (detailed) type rules of Ada in order to
make a solid attempt at making sense out of the availability rules. I'm
writing this as stream-of-consciousness, so I don't know how useful it will
be to the ARG in general, and I may never actually reach a conclusion. But
at least Tucker and Pascal ought to read it, and point out where it goes
wrong (if it goes wrong).

I'm essentially immediately stuck, because types do not have names, and
definitely do not follow the visibility rules. It appears that they always
exist. (Practically, they require semantic closure, but that's really an
implementation issue.) But I can't find anything in the standard that says
that.

If that wasn't true, then the classic example:

    package A is
       type Foo is range 1 .. 10;
    end A;

    with A;
    package B is
       V1, V2 : Foo := 1;
    end B;

    with B;
    procedure C is
    begin
       B.V1 := B.V2; -- Foo is not visible here.
    end C;

would be illegal. But it clearly is not.

OTOH, the properties of a type are controlled by visibility. That is, which
view of a type is used is controlled by visibility:

    package D is
        type P is private;
        Con : constant P;
    private
        type P is new Integer;
        Con : constant P := 1;
    end D;

    package D.Child is
        type Bar1 range 0 .. Con; -- Illegal, full view not visible (so not
integer type).
    private
        type Bar2 range 0 .. Con; -- Legal, full view visible.
    end D.Child;

While I can't find the actual rules that make this so, this IS the way
things work. (Are you with me so far??) [I chose type declarations here,
because it is one of very few places where this is a resolution rather than
legality rule. If only legality rules are involved, this is clearly easier.]

As a practical matter, the types that exist are those in the semantic
closure. That's simply because compilers can't have every type that might
exist in their symbol table, and other rules of the language insure that
types not in the semantic closure can't be used in any way.

The important point here is that the name of a type has absolutely no
relevance to its usability.

Now, in both child type stubs (type C.T) and in the type stubs that I'm
working on, if the completion is in the semantic closure, then the stub also
must be in the closure. (I don't believe that this is true for Limited With,
which may make the problem harder; thankfully I don't have to solve that
problem.)

Let's assume that the stub and completion are views of the same type. That
seems like the easiest model to work from, as it is similar to the models
for private types and existing incomplete types.  (This has NOTHING to do
with the names of the stub and completion. I've said nothing about names,
and don't expect to ever in this discussion. After all, only subtypes have
names, and a subtype is not a type. Reread 3.2 & 3.2.1 if necessary. :-)

Clearly, in any case of interest, the type has to be in the semantic closure
(the stub and completion are the same type). Otherwise, no object could
exist, and there is nothing that we could do. So we're only interested in
what rules we need concerning the properties of the type (which allows us to
bring in visibility if we need to).

It's also clear, that if the completion of the type is not in the semantic
closure, we can only have incomplete type properties.

The natural rule is that if the completion of the type is in the semantic
closure, then the properties of the complete type can be used. That allows
the examples that we want to work to work without any handstands. However,
this has a nasty ripple effect, where the addition or deletion of a context
clause on a unit can change the legality of a distant unit. Besides making
incremental compilation impossible (giving Rational heartburn), this is very
bad for maintenance and modularity of code.

This leads to my asking why we don't have this problem in Ada 95 as it is.
The answer appears to be that the rules of the language were carefully
constructed to prevent ever 'exporting' a  more capable view into a unit
that has less visibility. That is, the only places where a more capable view
can be used is where it is 'naturally' available; subtyping and renames
can't change that. For instance, the full view of a private type cannot be
subtyped in the visible part of a non-private child. And the private part of
a renamed package remains private.

Of course, this brings up the question of whether some rules would have the
same effect for type stubs (and its relatives). In order to accomplish that,
we'd pretty much have to ban any use of the completing type to declare
objects or components outside of that package. That pretty much would
eliminate the intended use of the feature.

But its important to realize that the visibility of a type appears to depend
on where it is originally declared. We're not taking about visibility of
names (which of course can be subtyped and/or renamed), but of the type
itself. Since types never have names, the only thing that has visibility
that we could be talking about is the declaration itself (as that's what 8.3
talks about).

This distinction is irrelevant for private types (and original incomplete
types), because the places that have visibility on the full declaration are
the only ones that can use the full view. So the visibility of the name is
the same as the visibility of the type. Any renames/subtypes have the same
visibility as the original type (you don't get to look in the private part
of a rename just because its a rename).

That means, in fact, that visibility IS the right model here, as long as it
is clear that it is the visibility of the original completing declaration
that we are talking about, and not the visibility of some subtype name that
happens to be declared somewhere else. This does have the unfortunate effect
that library-level renames aren't good enough for this purpose, but perhaps
a special rule to allow them would be worthwhile.

In particular, it is not necessary to exclude subtypes or renames, because
they have no impact on the visibility of the type (as opposed to the
visibility of some subtype of the type).

This means that Tucker's original wording is correct, but that the meaning
is essentially what his e-mail attempts at wording say. He's just hung up on
the name of a type, which is completely irrelevant (since types don't have
names).

Since only the visibility of the original declaration (or library-level
renaming of the original declaration's package) matter, no ripple effects
are possible. No with, no complete type operations.

'Extra' availablility (as in the assignment of two objects) is always
available (as the type always exists, at least in theory). Since that is the
case, there is no ripple effects possible.

This brings up the question of whether the requirement that the completion
'see' the stub is really necessary. It doesn't seem to be necessary for the
purpose of availability rules.

We do need such a rule by the discussion of Padua question #1: "Does the
completion know about incomplete type? (This is an implementation issue.)
Some implementations need to know whether there are any incomplete types
around. That may change the choice of representations for access types, etc.
This should be yes; but an implementation can handle this with contortions
or we could add an Implementation Permission. The group feels that this is
important enough to some implementations that we have to require it."

I don't quite understand the issue here. It seems that the incomplete type
might want to know the full type for that purpose, but that isn't possible
in general (with any mutually dependent type solution). I don't see much
advantage in knowing the reverse, unless the compiler just wants to use
"assume-the-worst" everywhere in that case.

I think that's it.

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

From: Tucker Taft
Sent: Thursday, March 20, 2003  1:48 PM

Randy Brukardt wrote:
>
> I'm trying to get a handle on the (detailed) type rules of Ada in order to
> make a solid attempt at making sense out of the availability rules. I'm
> writing this as stream-of-consciousness, so I don't know how useful it will
> be to the ARG in general, and I may never actually reach a conclusion. But
> at least Tucker and Pascal ought to read it, and point out where it goes
> wrong (if it goes wrong).
>
> I'm essentially immediately stuck, because types do not have names, and
> definitely do not follow the visibility rules. It appears that they always
> exist. (Practically, they require semantic closure, but that's really an
> implementation issue.) But I can't find anything in the standard that says
> that.

Types don't "always exist."  They exist between their elaboration
and the end of the lifetime of their scope.  For library-level types,
that means pretty much "forever."  I suspect though you are talking
about compile-time legality.  In that case, what generally matters
is "scope" rather than visibility.  Scope for declarations
is generally transitive whereas visibility isn't (when dealing with "with"
clauses, that is).

> If that wasn't true, then the classic example:
>
>     package A is
>        type Foo is range 1 .. 10;
>     end A;
>
>     with A;
>     package B is
>        V1, V2 : Foo := 1;
>     end B;
>
>     with B;
>     procedure C is
>     begin
>        B.V1 := B.V2; -- Foo is not visible here.

But Foo is "in scope".

>     end C;
>
> would be illegal. But it clearly is not.

"Foo" is in scope.

>
> OTOH, the properties of a type are controlled by visibility. That is, which
> view of a type is used is controlled by visibility:

No, I think this is mostly "scope" based rather than "visibility" based,
though when two declarations in scope, what matters is which one
is "hidden from all visibility."  Perhaps "hidden from all visibility" ought
to be renamed "temporarily not in scope."

>     package D is
>         type P is private;
>         Con : constant P;
>     private
>         type P is new Integer;
>         Con : constant P := 1;
>     end D;
>
>     package D.Child is
>         type Bar1 range 0 .. Con; -- Illegal, full view not visible (so not
> integer type).
>     private
>         type Bar2 range 0 .. Con; -- Legal, full view visible.
>     end D.Child;
>
> While I can't find the actual rules that make this so, this IS the way
> things work. (Are you with me so far??) [I chose type declarations here,
> because it is one of very few places where this is a resolution rather than
> legality rule. If only legality rules are involved, this is clearly easier.]
>
> As a practical matter, the types that exist are those in the semantic
> closure. That's simply because compilers can't have every type that might
> exist in their symbol table, and other rules of the language insure that
> types not in the semantic closure can't be used in any way.

Because they are out of scope.

>
> The important point here is that the name of a type has absolutely no
> relevance to its usability.

I'm not sure what you mean by that.  The actual identifier used is
not particularly relevant.  But the location of its declaration
is highly relevant, because only within the scope of that
declaration can you "use" the type.  The tricky part is when
there are two (or more) declarations that provide different
views of the "same" type.  The location of those two declarations
is highly relevant to a given use of the type.  If only one is
in scope, that that one clearly determines what happens.  When
both are in scope, then we have to presume that one "trumps" the
other.  According to 8.3(19) a completion, if in scope, "trumps"
the declaration it completes.  However, with the various AI-217
proposals, that may be too simplistic, since scopes are transitive
through "with" clauses.  I claim that we should adjust 8.3(19) to
make it work the way we want for whatever AI-217 proposal we adopt.
I suspect we will want to have the completion "trump" the original
declaration only when it is visible, and perhaps only when the
enclosing library package declaration, or a library unit renaming
thereof, is visible.

>
> Now, in both child type stubs (type C.T) and in the type stubs that I'm
> working on, if the completion is in the semantic closure, then the stub also
> must be in the closure. (I don't believe that this is true for Limited With,
> which may make the problem harder; thankfully I don't have to solve that
> problem.)
>
> Let's assume that the stub and completion are views of the same type. That
> seems like the easiest model to work from, as it is similar to the models
> for private types and existing incomplete types.  (This has NOTHING to do
> with the names of the stub and completion. I've said nothing about names,
> and don't expect to ever in this discussion. After all, only subtypes have
> names, and a subtype is not a type. Reread 3.2 & 3.2.1 if necessary. :-)

Perhaps the identifiers are not important, but the location of the *declarations*
is important, both to scope and to the rules for "hidden from all visibility."
One of the problems is that in the existing RM, we don't explicitly deal
with the problem that when you dereference a type that when declared,
was access-to-incomplete, it "magically" becomes access-to-complete in
certain locations.  I claim those are exactly the places where the incomplete
type declaration is hidden from all visibility according to 8.3(19), but
I don't see any explicit words to that effect.  It seems like 4.1(9) should
probably talk about this more explicitly.  We might be able to leave 8.3(19)
the way it is, and just add words to 4.1(9) to control when we want ".all"
to be of the compete type rather than the incomplete type.

Similarly, we could beef up 3.10.1(5-10) to identify what happens when you
have a name that "denotes" an incomplete type declaration -- whether it
is illegal (because the complete type and/or its enclosing package is visible,
say) or whether it in fact denotes the complete type.

...
> We do need such a rule by the discussion of Padua question #1: "Does the
> completion know about incomplete type? (This is an implementation issue.)
> Some implementations need to know whether there are any incomplete types
> around. That may change the choice of representations for access types, etc.
> This should be yes; but an implementation can handle this with contortions
> or we could add an Implementation Permission. The group feels that this is
> important enough to some implementations that we have to require it."
>
> I don't quite understand the issue here. It seems that the incomplete type
> might want to know the full type for that purpose, but that isn't possible
> in general (with any mutually dependent type solution). I don't see much
> advantage in knowing the reverse, unless the compiler just wants to use
> "assume-the-worst" everywhere in that case.

It is quite helpful in implementations that sometimes use fat pointers
to unconstrained array subtypes to know whether there are any incomplete
views that exist.  Or more precisely, it is helpful to know there might
exist access-to-incomplete types that are *not* aware that the full type is an unconstrained
array.  If the full type can always "see" the incomplete type declaration,
then it is aware that the incomplete type exists, and whether access-to-incomplete
types might be declared, so it can arrange that the fat pointer is *never*
used for access types to this type.

>
> I think that's it.

I pretty much agree with your analysis.  I maintain that 8.3(19) is
still the critical issue, and its implicit connection with 4.1(9) and
3.10.1(5).  We might want at least to make more explicit the connection between
"hidden from all visibility" and the designated type mentioned in 4.1(9).
Since 3.10.1(5) uses the term "denotes" it is clearly linked to visibility.

I suppose a different place to "fix" 4.1(9) and 3.10.1(5) is 8.6(16-18)
where it talks about denoting a declaration vs. denoting a view.
These 3 paragraphs are talking about the "current instance" stuff, but
could perhaps also deal with incomplete/complete view decisions.

And let's not forget 8.6(20-25) where we want to add our extended
matching rules between complete and incomplete views, though
I think that is a pretty independent problem, and needn't be
burdened with ripple-effect concerns.

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

From: Randy Brukardt
Sent: Thursday, March 20, 2003  4:59 PM

Tucker replied to my stream-of-consciousness:
...

> Types don't "always exist."  They exist between their elaboration
> and the end of the lifetime of their scope.  For library-level types,
> that means pretty much "forever."  I suspect though you are talking
> about compile-time legality.  In that case, what generally matters
> is "scope" rather than visibility.  Scope for declarations
> is generally transitive whereas visibility isn't (when dealing with "with"
> clauses, that is).

OK. I was thinking that this morning, anyway.

> > OTOH, the properties of a type are controlled by visibility. That is,
which
> > view of a type is used is controlled by visibility:
>
> No, I think this is mostly "scope" based rather than "visibility" based,
> though when two declarations in scope, what matters is which one
> is "hidden from all visibility."  Perhaps "hidden from all visibility"
ought
> to be renamed "temporarily not in scope."

That's confusing (if right). The "partial view" and the "full view" of a
private type are the same type, just different views. Similarly (or at
least, it ought to be similarly!) the "incomplete view" and "complete view"
are different views of the same type.

Conceptually, it makes more sense to talk about when the properties of a
particular view are available rather than to talk about when the "lesser" of
two views is hidden.

(Which reminds me of a issue that Pascal worried about: the three view type.
That's not a problem if you look at a type's different views having
increasing capability. At least as long as the different more restricted
views have properties which are a strict subset of the less restricted
view.)

I don't suppose it actually matters in practice. What worries me about
talking about hiding something is that if you get it wrong, you've got two
things sitting around, and confusion. If you talk about capabilities, the
worst that happens is you have less capability than you ought to.

> > The important point here is that the name of a type has absolutely no
> > relevance to its usability.
>
> I'm not sure what you mean by that.  The actual identifier used is
> not particularly relevant.  But the location of its declaration
> is highly relevant, because only within the scope of that
> declaration can you "use" the type. The tricky part is when
> there are two (or more) declarations that provide different
> views of the "same" type.  The location of those two declarations
> is highly relevant to a given use of the type.  If only one is
> in scope, that that one clearly determines what happens.  When
> both are in scope, then we have to presume that one "trumps" the
> other.  According to 8.3(19) a completion, if in scope, "trumps"
> the declaration it completes.  However, with the various AI-217
> proposals, that may be too simplistic, since scopes are transitive
> through "with" clauses.  I claim that we should adjust 8.3(19) to
> make it work the way we want for whatever AI-217 proposal we adopt.
> I suspect we will want to have the completion "trump" the original
> declaration only when it is visible, and perhaps only when the
> enclosing library package declaration, or a library unit renaming
> thereof, is visible.

Right. It's the location of the declaration, not the name. And, since
renamings and subtyping can't change the location of the declaration, only
the name, they don't matter.

And, I think I've come around to your "fix 8.3(19)" position. (It only took
two months. :-)

...
> One of the problems is that in the existing RM, we don't explicitly deal
> with the problem that when you dereference a type that when declared,
> was access-to-incomplete, it "magically" becomes access-to-complete in
> certain locations.  I claim those are exactly the places where the
incomplete
> type declaration is hidden from all visibility according to 8.3(19), but
> I don't see any explicit words to that effect.  It seems like 4.1(9)
should
> probably talk about this more explicitly.  We might be able to leave
8.3(19)
> the way it is, and just add words to 4.1(9) to control when we want ".all"
> to be of the compete type rather than the incomplete type.

Humm.

> Similarly, we could beef up 3.10.1(5-10) to identify what happens when you
> have a name that "denotes" an incomplete type declaration -- whether it
> is illegal (because the complete type and/or its enclosing package is
visible,
> say) or whether it in fact denotes the complete type.

I think that's what we did in the earlier type stubs.

If you believe the model that an incomplete type and the completing type are
just views of the same type, then the existing 3.10.1(10) only needs a minor
tweak:

    A dereference (whether implicit or explicit - see 4.1) shall not be of
an incomplete view.

(And we'd have to define "incomplete view" somewhere.)


...
> > I don't quite understand the issue here. It seems that the incomplete
type
> > might want to know the full type for that purpose, but that isn't
possible
> > in general (with any mutually dependent type solution). I don't see much
> > advantage in knowing the reverse, unless the compiler just wants to use
> > "assume-the-worst" everywhere in that case.
>
> It is quite helpful in implementations that sometimes use fat pointers
> to unconstrained array subtypes to know whether there are any incomplete
> views that exist.  Or more precisely, it is helpful to know there might
> exist access-to-incomplete types that are *not* aware that the full type
> is an unconstrained array.  If the full type can always "see" the
incomplete
> type declaration, then it is aware that the incomplete type exists, and
whether
> access-to-incomplete types might be declared, so it can arrange that the
fat
> pointer is *never* used for access types to this type.

OK, that's what I meant by assume-the-worst.

Anyway, the question is moot, because I found a much better reason for the
requirement. With the requirement, we can make all of the checks for
'correct' completion when we see the completing type. There is no need to do
those at some place where the two types intersect. That's enough of a
simplification in implementation (if not in the words) and in understanding
to make it worth the rule. That fact that it helps implementations as well
is a bonus.

> I pretty much agree with your analysis.  I maintain that 8.3(19) is
> still the critical issue, and its implicit connection with 4.1(9) and
> 3.10.1(5).  We might want at least to make more explicit the connection
between
> "hidden from all visibility" and the designated type mentioned in 4.1(9).
> Since 3.10.1(5) uses the term "denotes" it is clearly linked to
visibility.

I'd suggest defining "incomplete view" similarly to 7.3(15); then 4.1(9) can
be left alone. Adjustments to 8.3(19) are needed to determine which view is
being used. (I'm presuming that the wording for this for private types is OK
and can be borrowed where necessary.) Also, by using "view" here, the
intersection of the rules for incomplete and for private (which happens if
we allow completion by a private type) shouldn't give trouble. 3.10.1(5)
would then talk about denoting an incomplete view.

> I suppose a different place to "fix" 4.1(9) and 3.10.1(5) is 8.6(16-18)
> where it talks about denoting a declaration vs. denoting a view.
> These 3 paragraphs are talking about the "current instance" stuff, but
> could perhaps also deal with incomplete/complete view decisions.

I think I'd rather piggyback on the partial view/full view rules we already
have. That should make Pascal more conformable with multiple view types, as
the model would be unified.

> And let's not forget 8.6(20-25) where we want to add our extended
> matching rules between complete and incomplete views, though
> I think that is a pretty independent problem, and needn't be
> burdened with ripple-effect concerns.

There's nothing to extend if they are two views of the same type - we get
'matching' for free. We can use legality rules to get rid of any cases that
we don't want (there don't seem to be many of those!).

Where I got stuck was that the dereferencing rules talk about "covering the
completion". Since it's just a view of the same type, that's a meaningless
statement.

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

From: Tucker Taft
Sent: Thursday, March 20, 2003  9:57 PM

Randy Brukardt wrote:
...
> That's confusing (if right). The "partial view" and the "full view" of a
> private type are the same type, just different views. Similarly (or at
> least, it ought to be similarly!) the "incomplete view" and "complete view"
> are different views of the same type.
>
> Conceptually, it makes more sense to talk about when the properties of a
> particular view are available rather than to talk about when the "lesser" of
> two views is hidden.

I'm not sure what is the significant difference,
but whatever...

>
> (Which reminds me of a issue that Pascal worried about: the three view type.
> That's not a problem if you look at a type's different views having
> increasing capability. At least as long as the different more restricted
> views have properties which are a strict subset of the less restricted
> view.)

Actually, we must remember that there
can be multiple "views" of the same type (7.3.1(3-4)),
because the properties can be revealed incrementally.
A type might initially appear limited, because one of
its components is limited private.  Then it may turn out
that the full type of the component is non-limited, causing
the enclosing type to become nonlimited.  Similarly,
an array might initially be an array-of-private, and
then turn out to be an array-of-boolean, picking up
"and" and "or", etc.

>
> I don't suppose it actually matters in practice. What worries me about
> talking about hiding something is that if you get it wrong, you've got two
> things sitting around, and confusion. If you talk about capabilities, the
> worst that happens is you have less capability than you ought to.

I'm not sure why one of these is worse than the other.


> ...
>
> If you believe the model that an incomplete type and the completing type are
> just views of the same type, then the existing 3.10.1(10) only needs a minor
> tweak:
>
>     A dereference (whether implicit or explicit - see 4.1) shall not be of
> an incomplete view.
>
> (And we'd have to define "incomplete view" somewhere.)

But I thought our extended matching rules would
change this, so that dereference *could* be
incomplete, so long as they are matched against
something that is complete.

> ...
>>And let's not forget 8.6(20-25) where we want to add our extended
>>matching rules between complete and incomplete views, though
>>I think that is a pretty independent problem, and needn't be
>>burdened with ripple-effect concerns.
>
>
> There's nothing to extend if they are two views of the same type - we get
> 'matching' for free. We can use legality rules to get rid of any cases that
> we don't want (there don't seem to be many of those!).

Hmmm... I'm not sure that works, since 8.6 talks about
properties of the type (e.g. being an access type, or
being covered by some class-wide type).
Presumably those are properties of the "view" --
a dereference of an access-to-incomplete is presumably
an incomplete view, so it would not be known whether
it was an access type, or whether it was covered by
some class-wide type (unless the class-wide type were
the same-incomplete-type'Class).

> Where I got stuck was that the dereferencing rules talk about "covering the
> completion". Since it's just a view of the same type, that's a meaningless
> statement.

I don't quite agree.  When you have an incomplete view,
you don't know whether it is covered by some arbitrary
class-wide type.  You need to "consult" the completion
to know that.  We need to decide when you are allowed
to consult the completion.  I have a feeling we are perhaps
being a bit too generous already.

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

From: Randy Brukardt
Sent: Friday, March 21, 2003  6:39 PM

> > I don't suppose it actually matters in practice. What worries me about
> > talking about hiding something is that if you get it wrong, you've got two
> > things sitting around, and confusion. If you talk about capabilities, the
> > worst that happens is you have less capability than you ought to.
>
> I'm not sure why one of these is worse than the other.

Because in the second case, things are well-defined (you have less
capability). In the first case, you have two views of the same thing visible
simultaneously, and there is nothing in the language to say how that gets
resolved. It means immediate work for the ARG; in the second case, the ARG
only has to work if the missing capability is actually important (and that's
rare).

> > ...
> >
> > If you believe the model that an incomplete type and the completing type are
> > just views of the same type, then the existing 3.10.1(10) only needs a minor
> > tweak:
> >
> >     A dereference (whether implicit or explicit - see 4.1) shall not be of
> > an incomplete view.
> >
> > (And we'd have to define "incomplete view" somewhere.)
>
> But I thought our extended matching rules would
> change this, so that dereference *could* be
> incomplete, so long as they are matched against
> something that is complete.

Those aren't matching rules. I'm very against context-specific type
matching, because it's conceptually ugly (what happens depends on context)
and because we use a single routine to do all type matching, based solely on
the type ids (which always exist in our compilers; they don't have any
scoping/visibility themselves).

Anyway, the rules as written in AI-00217-04 only talk about when a
dereference is legal; it has nothing to do with "type matching". There are
just some additional cases where a dereference of an incomplete type is
legal. And yes, I do mean to have those described at this point in the text.

I note that the AI-00217-07 that you submitted has precisely the same
legality rules; there is no change to 8.6 and certainly no extension of type
matching.

> ...
> > There's nothing to extend if they are two views of the same type - we get
> > 'matching' for free. We can use legality rules to get rid of any cases that
> > we don't want (there don't seem to be many of those!).
>
> Hmmm... I'm not sure that works, since 8.6 talks about
> properties of the type (e.g. being an access type, or
> being covered by some class-wide type).
> Presumably those are properties of the "view" --
> a dereference of an access-to-incomplete is presumably
> an incomplete view, so it would not be known whether
> it was an access type, or whether it was covered by
> some class-wide type (unless the class-wide type were
> the same-incomplete-type'Class).

The anonymous access case is irrelevant; an incomplete type cannot be
completed by an anonymous type (we got rid of named anonymous access types,
thank heaven). And access-to-incomplete of course is covered by the existing
rule.

> > Where I got stuck was that the dereferencing rules talk about "covering the
> > completion". Since it's just a view of the same type, that's a meaningless
> > statement.
>
> I don't quite agree.  When you have an incomplete view,
> you don't know whether it is covered by some arbitrary
> class-wide type.  You need to "consult" the completion
> to know that.  We need to decide when you are allowed
> to consult the completion.  I have a feeling we are perhaps
> being a bit too generous already.

You're right of course that an arbitrary coverage needs to refer to the
completion. But is that really worth it? All of the cases that I've seen
either were making a class-wide call to Incomplete'Class (using
access-to-Incomplete'Class) or are assigning concrete instances of
Incomplete to Complete. The former is useful to make sense out of the extra
packages necessary for this (to make them useful for more than just breaking
cycles); I'm not sure that the latter is really valuable in practice.

So I have to wonder the value of messing with these rules. After all, any
case where these rules would kick in can easily be worked around simply by
withing the completion's package. I'd guess that 98% of the time, that will
be necessary anyway, unless my classwide idea becomes popular. And even
then, we don't need to change type matching. I think we'll need some
experience using whatever facility we choose before we'll know if we really
need something fancy.

I would be happy simply making this a part of tagged incomplete types:

   A dereference (...) shall not be of an incomplete type, unless it is a
tagged incomplete type directly used as an actual parameter to a
non-dispatching call.

forgetting all of the rest of it until we can see if in fact it comes up in
practice. (We'll need some implementations to do that.) But I'm willing to
go further, but not so far as to mess with type matching.


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

From: Randy Brukardt
Sent: Friday, March 21, 2003  7:02 PM

> The question is: is the limited (or incomplete if you prefer) view of
> P.T hidden from all visibility in R?  If I read Tuck's proposed change
> to 8.3(19) it seems that the answer is a resounding Yes.

There's no way to tell; I haven't seen any real proposal for limited with
yet. I've only been discussing the two versions of type stubs - the original
one I'm working on, and Tucker's child type stubs.

My (very superficial) analysis of 'limited with' suggests that it will have
much worse visibility issues than either version of type stubs.

Anyway, let's look at this example from the point of view of type stubs
(note: in type stubs, "limited with" does nothing other than make the
package available):

    limited with P;
    with Q;
    package R is
        X : P.T; -- Legal? (No, no P.T here.)
        type T is separate of P.T;
        Y : T; -- Legal? (No, T is incomplete.)
    end R;

OK, that's probably not quite the same example. Let's try again:

    limited with P;
    package S is
        type T is separate of P.T;
    end S;

    with Q, S;
    package U is
        X : P.T; -- Legal? (No, no P.T here.)
        Y : S.T; -- Legal?
    end U;

> The reason is that 8.3(14) says that "a declaration is visible within
> its scope, except when hidden from all visibility."  R is clearly part
> of the scope of P.T, because Q is a semantic dependent of P and R is a
> semantic dependent of Q.  And none of the "hidden from all visibility"
> rules apply to P.T here (see 8.3(15-20)).  So the completion of P.T is
> visible in R, and the incomplete view of P.T is hidden from all
> visibility.

Humm. This does seem to be the case (substituting U for R).

That seals it for me; I'll stick with a separate set of legality rules as
we'd previously written. We can't make the kind of changes to the visibility
rules that are contemplated by Tucker; it would take years to debug them
alone.

Thanks for simplifying my work. :-)

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

From: Pascal Leroy
Sent: Monday, March 24, 2003  7:24 AM

> I would be happy simply making this a part of tagged incomplete types:
>
>    A dereference (...) shall not be of an incomplete type, unless it is
> a tagged incomplete type directly used as an actual parameter to a
> non-dispatching call.
>
> forgetting all of the rest of it until we can see if in fact it comes up
> in practice.

In fact I have been wondering about this lately.  Why do we want these
new rules about dereferencing anyway?  What purpose do they serve?
Can't you just "with" the completion and be done with?  It seems to me
that the incomplete view would mostly be needed in specifications, and
that dereferencing would mostly be used in bodies, so I'm not sure what
good it would do to allow you to dereference without seeing the
completion.

The minutes of the Cupertino meeting have the explanation "Tucker would
like this to be legal" which seems like a rather weak justification to
me ;-)

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

From: Tucker Taft
Sent: Monday, March 24, 2003  12:04 PM

Perhaps you are right.  However, this means that
you have to be very aware whether a given access parameter
is dispatching or not, because there is an implicit
dereference of access parameters as a side-effect
of a dispatching call.  It seems a little unfriendly
to have to make this big distinction.

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

From: Gary Dismukes
Sent: Monday, March 24, 2003  12:30 PM

I agree that this special rule for dereferencing accesses to tagged
incomplete values doesn't appear to be very useful.  It seems like
it just makes the rules more complicated and harder to learn for
very little gain.  Just because the rule can be relaxed in the tagged
case doesn't mean it should be.

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

From: Randy Brukardt
Sent: Monday, March 24, 2003  12:14 PM

I don't see anything in the language which makes the dispatching case an
implicit_dereference. That seems like a hole for tagged incomplete types
(you really do need that to be illegal if you don't have the full type
around).

Pascal wrote:

> In fact I have been wondering about this lately.  Why do we want these
> new rules about dereferencing anyway? ...

See the examples I've sent out (twice) for one possible use. Note that I
admit that I probably could live without that if AI-230 is approved. But I'm
still not sure that (AI-230) is a good idea.

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

From: Pascal Leroy
Sent: Monday, March 24, 2003  2:14 PM

I guess I have a hard time believing that the body of CBuild_Menu doesn't
need to have a "with CBuild_Root_Definition" for other reasons, so it's hard
to get excited about the possibility to dereference Item.Dialog in the body
of CBuild_Menu.

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

From: Randy Brukardt
Sent: Monday, March 24, 2003   2:59 PM

No, there is nothing that you can use there that you couldn't make visible
in CBuild_Root. Since CBuild_Root_Definition is defining an abstract type,
there are no concrete object properties, and the only interesting operations
are dispatching or class-wide. So the only thing the CBuild_Menu can do with
an access-to-root-window is make a class-wide or dispatching call on it. By
including class-wide analogs to any operations in CBuild_Root_Definition,
all such calls can be made. In this actual case, the only things that the
menu package ever does with a window is: 1) dispatch on a routine to
generate code to make a call to create the window (as part of the code that
responses to the selection of a menu item); 2) dispatch on a routine that
actually opens a copy of the window (as part of the code that simulates the
actions of the GUI); 3) call a routine that looks up the window by name
(when reading the menu object from a file (this is class-wide, and defined
elsewhere anyway); and 4) dispatch on a routine that returns the name of the
window (to output into the file when writing a menu object).

The only thing that I can imagine wanting to do that you couldn't do is to
convert it to some specific type, in order to use operations of that type
not available on the root type. But that would be very bad object-oriented
design (you don't cast general things into more more specific types), and it
normally would be easy to add a dispatching routine to the root to handle
that generally.

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

From: Randy Brukardt
Sent: Tuesday, June 17, 2003  2:12 AM

Here is the implementation report I promised at the last meeting for all
three live AI-217
proposals. I know that these are really late, but at least you'll have three
days in which to read them. (Of course, if you're at Ada Europe already,
that probably is really about 3 minutes. :-(

[Editor's note: This report can be found in the !appendix of AI-217-7.]

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


Questions? Ask the ACAA Technical Agent