Version 1.2 of ais/ai-00326.txt

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

!standard 03.10.01 (02)          03-07-15 AI95-00326/02
!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 J.11 (00)
!class amendment 02-02-06
!status Amendment 200Y 03-07-15
!status ARG Approved 10-0-1 03-07-15
!status work item 02-12-13
!status received 02-02-06
!priority Medium
!difficulty Medium
!subject Tagged incomplete types
!summary
A concept of a "tagged incomplete" type is introduced, which is a type that has the same restrictions as an incomplete type except that it may also be used for a formal parameter.
!problem
For mutually recursive types, it is valuable if subprogram parameters may be of the type itself, rather than only an access to the type. However, for most types, it may be necessary to see the full definition to know how parameters of the type are passed. However, because tagged types are always passed by reference, there is no implementation difficulty in allowing them to be used as parameters even when the full definition of the type is not available. Hence, it makes sense to relax the rule for using incomplete types that are known to be tagged, to allow them as formal parameters, since from a code generation point of view they are essentially equivalent to access parameters.
!proposal
The syntax for an incomplete type declaration is amended as follows:
incomplete_type_declaration ::= type defining_identifier [discriminant_part] [is tagged];
If the words IS TAGGED appear, the type is a tagged incomplete type. Otherwise, the type is a non-tagged incomplete type. In addition to places where a (non-tagged) incomplete type may be used, a tagged incomplete type may be used as a formal parameter type. The attribute 'Class is defined for (specific) tagged incomplete types. (The use of 'Class with non-tagged incomplete types is considered obsolescent; such non-tagged incomplete types must be completed with a tagged type.) The class-wide type denoted by the Class attribute of an incomplete tagged type is also an incomplete tagged type. An incomplete tagged type declaration must be completed by a tagged type declaration.
!wording
Replace 3.10.1(2):
incomplete_type_declaration ::= type defining_identifier [discriminant_part] [is tagged];
Modify 3.10.1(4):
Add a new first sentence:
If an incomplete_type_declaration includes the keyword TAGGED, then a type_declaration that completes it shall declare a tagged type.
Replace 3.10.1(5-9):
A name that denotes an incomplete_type_declaration may be used as follows:
* as the subtype_mark in the subtype_indication of an access_to_object_definition; the only form of constraint allowed in this subtype_indication is a discriminant_constraint;
* as the subtype_mark defining the subtype of a parameter or result of an access_to_subprogram_definition;
* as the subtype_mark in an access_definition;
A name that denotes an incomplete_type_declaration that includes the keyword TAGGED may also be used as follows:
* as the subtype_mark defining the subtype of a parameter in a formal_part;
* as the prefix of an attribute_reference whose attribute_designator is Class; such an attribute_reference is restricted to the uses allowed above.
Replace 3.10.1(11):
An incomplete_type_declaration declares an incomplete type and its first subtype; the incomplete type is tagged if the keyword TAGGED appears; the first subtype is unconstrained if a known_discriminant_part appears.
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, 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
Tagged type hierarchies often have need for mutually dependent types. By allowing a tagged incomplete type to be used as a formal parameter type, access parameters may be avoided in such mutually dependent type situations. This proposal gains additional power when combined with the proposals for allowing mutually dependent types to be defined in separate packages.
We are not allowing an incomplete tagged type to be used as a return type, because of the many special rules and implementation issues associated with returning tagged types (e.g. abstract types may not be used as result types, functions that must be overridden, accessibility checks on returning limited by-reference types, dispatching on result coupled with tag indeterminacy, finalization associated with returning potentially controlled types, etc.).
!example
!corrigendum 3.10.1(2)
Replace the paragraph:
incomplete_type_declaration ::= type defining_identifier [discriminant_part];
by:
incomplete_type_declaration ::= type defining_identifier [discriminant_part] [is tagged];
!corrigendum 3.10.1(4)
Replace the paragraph:
If an incomplete_type_declaration has a known_discriminant_part, then a full_type_declaration that completes it shall have a fully conforming (explicit) known_discriminant_part (see 6.3.1). If an incomplete_type_declaration has no discriminant_part (or an unknown_discriminant_part), then a corresponding full_type_declaration is nevertheless allowed to have discriminants, either explicitly, or inherited via derivation.
by:
If an incomplete_type_declaration includes the keyword tagged, then a type_declaration that completes it shall declare a tagged type. If an incomplete_type_declaration has a known_discriminant_part, then a type_declaration that completes it shall have a fully conforming (explicit) known_discriminant_part (see 6.3.1). If an incomplete_type_declaration has no discriminant_part (or an unknown_discriminant_part), then a corresponding type_declaration is nevertheless allowed to have discriminants, either explicitly, or inherited via derivation.
!corrigendum 3.10.1(5)
Replace the paragraph:
The only allowed uses of a name that denotes an incomplete_type_declaration are as follows:
by:
A name that denotes an incomplete_type_declaration may be used as follows:
!corrigendum 3.10.1(8)
Replace the paragraph:
by:
A name that denotes an incomplete_type_declaration that includes the keyword tagged may also be used as follows:
!corrigendum 3.10.1(9)
Replace the paragraph:
by:
!corrigendum 3.10.1(11)
Replace the paragraph:
An incomplete_type_declaration declares an incomplete type and its first subtype; the first subtype is unconstrained if a known_discriminant_part appears.
by:
An incomplete_type_declaration declares an incomplete type and its first subtype; the incomplete type is tagged if the keyword tagged appears; the first subtype is unconstrained if a known_discriminant_part appears.
!corrigendum J.11(1)
Insert new clause:
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.
!ACATS Test
ACATS B and C tests should be constructed for this AI.
!appendix

This AI was split out of AI-00217-05 (and other variants), in order to
simplify those proposals and to insure that this idea gets considered no
matter which of those proposals is adopted.

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

From: Randy Brukardt
Sent: Tuesday, July 15, 2003  2:25 PM

In Toulouse, we discussed whether we could allow dereferences of tagged
incomplete types. In general, the answer is no, because we cannot know where
tags and discriminants are going to be stored in the completing type. (If
the type is completed in the body, for instance.)

The conversation in Toulouse focused on dispatching calls. Clearly, we
cannot allow dispatching calls because we don't know where the tag is stored
(presuming the implementation allows positioning it, as Rational Apex and
Janus/Ada do).

However, there is no problem with class-wide calls, and these could be
useful. The key is that we can only allow "whole-object" dereferences when
the dereference is immediately passed as a reference parameter. This would
look something like:

      package Typ is
          type T is tagged;
          type AT is access all T;
          procedure Op1 (Obj : in out T'Class);
          procedure Op2 (Obj : in out T);
          ...
      end Typ;

      with Typ;
      procedure User is
          ...
          P : Typ.AT := ...;
          ...
          Typ.Op1 (P.all); -- Allowed? (No implementation problem).
          Typ.Op2 (P.all); -- Can't allow (don't know where the tag is).
          ...
      end User;

Note that Op1 could be used as a work-around to implement Op2 if that was
necessary (as the body of Typ.Op1 certainly could dispatch to Op2).

This rule would be on the messy side (it pretty much could only allow
dereferences when used as a non-dispatching actual parameter) and I haven't
tried to figure out the wording.

Should we pursue this, or leave that AI without any means of making a call?

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

From: Randy Brukardt
Sent: Tuesday, July 15, 2003  2:41 PM

I neglected to mention that class-wide parameters would be the most likely
way that a tagged incomplete type would be used from a limited with (you
almost always should avoid non-dispatching specific tagged parameters,
because they cause trouble if there is an extension). So, such a class-wide
call may not be rare:

    package Office is
        type Department is tagged private;
        type Dept_Ptr is access all Department'Class;
    private
        ...
    end Office;

    limited with Office;
    package Employees is
        type Employee is tagged private;
        type Emp_Ptr is access all Employee'Class;
        procedure Assign_Employee(E : in out Employee;
                                  D : in out Office.Department'Class);
        ...
        function Current_Department(D : in Employee) return Office.Dept_Ptr;
    private
        ...
    end Employees;

    with Employees, Repository;
    procedure RRS is
        Randy, Ian, Isaac : Employees;
    begin
        -- Add a new employee in Randy's department:
        Repository.Read (Randy);
        Employees.Assign_Employee (Isaac, Employees.Current_Department (Randy).all);
        Repository.Write (Isaac);
    end RRS;

The call to Assign_Employee is illegal for a tagged incomplete type. We'd
have to with Office to make it legal, which is annoying, since this has
little to do with Office. (And, if we adopt a special rule to make it legal
here, which we've discussed, then it ought to be legal for tagged incomplete
as well -- otherwise, we'd have a weird inconsistency.)

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


Questions? Ask the ACAA Technical Agent