Version 1.5 of ai05s/ai05-0110-1.txt

Unformatted version of ai05s/ai05-0110-1.txt version 1.5
Other versions for file ai05s/ai05-0110-1.txt

!standard 12.5(20/2)          10-10-05 AI05-0110-1/01
!standard 12.5.1(21/3)
!class binding interpretation 08-08-08
!status work item 08-08-08
!status received 08-05-21
!priority Low
!difficulty Hard
!qualifier Omission
!subject Characteristics of generic formal derived type are not inherited
!summary
The model of inheritance for generic formal derived types is the same as that for a derived type declaration.
!question
Consider:
package pak1 is pragma elaborate_body;
type T1 is limited private;
generic type T2 is new T1; package pak2 is end pak2;
private type T1 is access Integer; end pak1;
package body pak1 is package body pak2 is x2 : T2 := null; -- Legal? end pak2; end pak1;
Neither 12.5.1(20/2) nor 12.5.1(21/2) appear to cover this case. What is the intent?
!recommendation
(See summary.)
!wording
In 3.4(7), italize "characteristics", add it to the index (in addition
to the definition in 7.3).
Replace 12.5.1(20/2)
If the ancestor type is a composite type that is not an array type, the formal type inherits components from the ancestor type (including discriminants if a new discriminant_part is not specified), as for a derived type defined by a derived_type_definition (see 3.4 and 7.3.1).
with
The characteristics of a formal derived type are defined as for a derived type defined by a derived_type_definition (see 3.4 and 7.3.1).
AARM note: Note that this includes the implicit declarations of inherited primitive subprograms.
Replace the beginning of 12.5.1 (21/3)
For a formal derived type, the predefined operators and inherited user-defined subprograms are determined by the ancestor type and any progenitor types, and are implicitly declared at the earliest place, if any, immediately within the declarative region in which within the immediate scope of the formal type is declared, where the corresponding primitive subprogram of the ancestor or progenitor is visible (see 7.3.1). In an instance, the copy of such an implicit declaration declares ...
with
In an instance, the copy of an implicit declaration of an inherited primitive subprogram of a formal derived type declares ...
!discussion
The model of inheritance for characteristics of a type is described in 3.4 and 7.3.1. Ada 95 did not use this model for formal derived types, rather repeating the wording in 12.5 and 12.5.1. (This appears be have occurred because the formal definition of "characteristics" was added late during the development of Ada 9x.) This wording repeat never seems to be quite, we are continually finding examples such as the one in the question.
Thus, rather than fixing the 12.5 wording, we eliminate it in favor of depending on the rules as described in 3.4 and 7.3.1. This is not intended to make a change to the language (other than in the example of the !question), just use a more consistent description.
We also add a definition and indexing for "characteristics" in 3.4, as this is where exactly what a characteristic is is defined.
--!corrigendum 12.5.1(21/2)
!ACATS Test
!appendix

!topic When are characteristics of generic formal derived type available?
!reference 7.3.1(4), 12.5.1(20-21)
!from Adam Beneschan 08-05-21
!discussion

This seems to be a corner case that may involve some missing wording in the RM:

    package pak1 is
       pragma elaborate_body;

       type T1 is limited private;

       generic
          type T2 is new T1;
       package pak2 is
       end pak2;

    private
       type T1 is access Integer;
    end pak1;

    package body pak1 is
       package body pak2 is
          x2 : T2 := null;   -- Legal?
       end pak2;
    end pak1;

7.3.1(4) discusses cases where a derived type is derived from a private type;
when the appropriate substitutions are made into the language of 7.3.1(3),
it says that additional "characteristics" of a type become visible for a
derived type at a place later in the declarative region where additional
characters of the parent type become visible.

However, 7.3.1(4) refers to a derived_type_definition.  The syntax of a
formal derived type in 12.5.1(2) is a formal_derived_type_definition, so
it's not obvious that 7.3.1(4) applies to it.

12.5.1(21) does imply that for a formal derived type, if predefined operators
and user-defined subprograms of the parent type become visible later, those
operators also become visible later; thus, if the full definition of T1 were
an enumeration type, the "<" and ">" operators on T2 would be visible in the
body of pak2 (but not the spec).  Similarly, 12.5.1(20) implies that components
are inherited for a formal derived type "as for" a derived_type_definition,
which I assume includes the rules in 7.3.1(4); thus, if the full type of T1
were a record with a component F, then this component would also be visible
for type T2 in the body of pak2.

But this example doesn't involve predefined or user-defined subprograms or
components, so it's not obvious that 12.5.1(20-21) apply to this example
either.  (Neither does AI05-29.)

I think the intent is for 7.3.1(4) to apply to generic formal derived types
just as for non-generic derived types; and while 12.5.1(20-21) do make some
of those "additional characteristics" available, it doesn't work for all
characteristics.  Perhaps "or formal_derived_type_definition" just needs
to be added to 7.3.1(4).

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

From: Randy Brukardt
Date: Thursday, August 7, 2008  9:58 PM

> 7.3.1(4) discusses cases where a derived type is derived from a
> private type; when the appropriate substitutions are made into the
> language of 7.3.1(3), it says that additional "characteristics" of a
> type become visible for a derived type at a place later in the
> declarative region where additional characters of the parent type
> become visible.

Unfortunately, this example seems to show that there is something weird
about 7.3.1(3/1) itself (which has nothing to do with generics). It talks
about the component types of composite types, and additional characteristics.
But the full type T1 is elementary! This is surely not an *additional*
charactistic, or one of a component type. It is a *different*, incompatible
characteristic!

Boiled down, the usual intepretation of this wording says that "If a
composite type and <some other stuff>, then the composite type is an
elementary type." I always thought that a type was either one or the
other (depending on its view and visibility on that view). This wording
only makes sense if it can be both at the same time.

Hopefully, someone else will take this AI when we assign it... ;-)

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

From: Adam Beneschan
Date: Friday, August 8, 2008  10:12 AM

> Boiled down, the usual intepretation of this wording says that "If a
> composite type and <some other stuff>, then the composite type is an
> elementary type." I always thought that a type was either one or the
> other (depending on its view and visibility on that view). This
> wording only makes sense if it can be both at the same time.

Hmmm... that's not how interpret it.  7.3.1(3/1) talks about composite
types and seems to apply mostly to things like arrays of private
types:

    type T1 is private;
    type T2 is array (natural range <>) of T1;

I don't think this rule applies to my code snippet, and I didn't intend
for it to.  What the RM appears to be saying in 7.3.1(4/1) is, "There is a
rule about derived types that looks just like 7.3.1(3/1) except that,
in essence, you replace 'composite types whose component type is private'
with 'derived types whose parent type is private'".
Or, actually, replace "composite" with "derived" and "component type"
with "parent type". So 7.3.1(4/1) doesn't really have anything to do with
composite types. If 7.3.1(4/1) were written without the "corresponding rule"
shorthand, I suppose it would look like:

"For a derived type, the characteristics (see 7.3) of the type are determined
in part by the characteristics of its parent type. At the place where the
derived type is declared, the only characteristics of parent types used
are those characteristics visible at that place. If later immediately
within the declarative region in which the derived type is declared within
the immediate scope of the derived type additional characteristics become
visible for the parent type, then any corresponding characteristics become
visible for the derived type. Any additional predefined operators are
implicitly declared at that place."

Maybe it should have been just been done that way---it would have been more
verbose but perhaps less confusing.

The point of my original question was: does this also apply to generic formal
derived types?

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

From: Pascal Leroy
Date: Wednesday, November 19, 2008  9:00 AM

> The point of my original question was: does this also apply to generic
> formal derived types?

I think that 12.5(8/2) (in particular the fifth sentence) answers this.
(And the answer is yes.)

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

From: Adam Beneschan
Date: Wednesday, November 19, 2008  9:33 AM

> (On a very old question from Adam.)

This is now AI05-0110, by the way.

...
> I think that 12.5(8/2) (in particular the fifth sentence) answers this.
>  (And the answer is yes.)

I don't think the fifth sentence of 12.5(8/2) applies. This sentence talks
about "predefined operators". "Predefined operator" is a very specific term
that refers to certain subprograms (see 6.6(1)), and describes where they
are implicitly declared. The example I gave didn't involve any operators.
It was more about the looser concepts of "operations" and "characteristics"
of a type; my example involved assignment and the "null" literal, neither
of which is an operator, and neither of which has an implicit declaration.

I suppose you could argue that what this sentence in 12.5(8/2) says about
operators should apply by analogy to other characteristics, but not without
a certain amount of hand-waving. (I still am not certain how much
hand-waving is acceptable in the RM/ISO Standard; I seem at times to be
a lot more bothered by it than others.  :-))

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

From: Pascal Leroy
Date: Wednesday, November 19, 2008  11:47 AM

I think you're right.  The best fix would probably be to talk about
"additional characteristics" in 12.5.1(20/2-21/2), although I have never
been too happy with this "characteristics" stuff, which is nowhere defined.
I wonder if it would be better to talk about "categories": if the categories
to which the parent type belongs change, the derived type belongs to the same
categories.

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

From: Randy Brukardt
Date: Wednesday, November 19, 2008  1:37 PM

That wouldn't work, because a component is considered a "characteristic",
but it surely doesn't have anything to do with "category" of a type. These
are both defined terms, after all. The characteristics of a type are
(loosely) defined in 7.3(16/2), and it is much broader than just a category.
(I see a tiny buglet in 7.3(16/2): it should say "classes and categories",
because as written, "categories" that aren't classes aren't included, and
that could lead something to think that limitedness (for example) is not a
characteristic.)

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

From: Randy Brukardt
Date: Thursday, November 20, 2008  6:41 PM

> (I see a tiny buglet in 7.3(16/2): it should say "classes and
> categories", because as written, "categories" that aren't classes
> aren't included, and that could lead something to think that
> limitedness (for example) is not a
> characteristic.)

This was wrong; characteristics are all about inheritance, but categories
that aren't classes aren't inherited. They're not interesting here since
that they're always given on the full declaration (or even the partial view
in some cases); there's no issue about becoming visible at a later point.
So it makes sense that these are not characteristics.

(That makes Pascal's comment about "categories" even more wrong, not that
"more wrong" matters much.)

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

From: Steve Baird
Date: Friday, July 23, 2010  6:59 PM

How about:

   !wording
'
   Replace 12.5.1(20/2)

     If the ancestor type is a composite type that is not an array type,
     the formal type inherits components from the ancestor type
     (including discriminants if a new discriminant_part is not
     specified), as for a derived type defined by a
     derived_type_definition (see 3.4 and 7.3.1).

   with

     The characteristics of a formal derived type are defined
     as for a derived type defined by a derived_type_definition
     (see 3.4 and 7.3.1).

     AARM note:
     If the ancestor type is a composite type that is not an array type,
     this means that the formal type inherits components from
     the ancestor type (including discriminants if a new
     discriminant_part is not specified) as fir a derived type defined
     by a derived_type_definition.

Is the AARM note even needed? I wouldn't include anything like that if
I were writing this from scratch.

The original question in the AI was about the legality of

   package pak1 is
     pragma elaborate_body;
     type T1 is limited private;
     generic
       type T2 is new T1;
     package pak2 is end pak2;
   private
     type T1 is access Integer;
   end pak1;

   package body pak1 is
     package body pak2 is
       x2 : T2 := null; -- Legal?
     end pak2;
    end pak1;

The legality of this example would then depend on 7.3.1's
   The corresponding rule applies to a type defined by a
   derived_type_definition, if there is a place immediately within the
   declarative region in which the type is declared within its immediate
   scope where additional characteristics of its parent type become
   visible.

The declaration of X2 is included in the declarative region in which the
formal derived type is declared, so I think the example is legal.

What do think of
    - the proposed wording
    - my interpretation of how it applies in the case of the example ?

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

From: Randy Brukardt
Date: Friday, July 23, 2010  7:30 PM

What worries me here is why this wasn't done in the first place. It seems to be
obvious wording and one thinks that there was some reason that it wasn't used.
(It causes implicit contracts?? Does other damage to the contract model?)

If there is no known reason, then this seems fine to me. I do think an AARM note
would be a good idea, but I'd probably make it more general:
    AARM Note: "characteristics" include components, <list of other interesting
    things here>, all of which are inherited as described in 7.3.1.

The example is clearly covered. It surely would be if we were talking about an
ordinary, non-generic derived type. I presume we want generics to work the same
way.

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

From: Steve Baird
Date: Tuesday, July 27, 2010  4:20 PM

So alternative #1 is

   Replace 12.5.1(20/2)
      If the ancestor type is a composite type that is not an array type,
      the formal type inherits components from the ancestor type
      (including discriminants if a new discriminant_part is not
      specified), as for a derived type defined by a
      derived_type_definition (see 3.4 and 7.3.1).

   with

      The characteristics of a formal derived type are defined
      as for a derived type defined by a derived_type_definition
      (see 3.4 and 7.3.1).

I'd say that no AARM note is needed because the text already gives a pointer to
3.4 which has a nice long section that starts with
    "The characteristics of the derived type are defined as follows:"
.

Alternative #2 is the even smaller change suggested in the !discussion section
of the AI: eliminate 12.5.1(20/2) and add a few words to 7.3.1(4):

   The corresponding rule applies to a type defined by a
   derived_type_definition {or formal_derived_type_definition
   (see 12.5.1)}, if there is a place immediately within the
   declarative region in which the type is declared
   where additional characteristics of its parent type become visible.

This is even more concise and it has the advantage of listing all the
"corresponding rule applies" cases in one place. It has the drawback of
introducing a forward reference - chapter 7 is not where we normally want to
talk about formal derived types.

What do you think?

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

From: Randy Brukardt
Date: Tuesday, July 27, 2010  5:18 PM

I'd go with the first; we try pretty hard to say as little as possible about
generic types before chapter 12.

Do you have any theory as to why this wasn't done in the first place? What
worries me is that there originally was some good reason for not doing this,
since it seems like the obvious solution. (Of course, we've beefed up the
characteristics wording several times, so perhaps it just wasn't up to the job
in 1994. Tucker, do you have any insight??)

I'm not worried about the Ada 2005 patch (which probably was a minimum change to
fix the known bug), but why this wasn't done originally.

Humm, "characteristics" include inherited subprograms (3.4(17/2)). That means
this suggestion would conflict with 12.5.1(21/2) (actually 12.5.1(21/3) after
more changes for AI05-0029-1). I've often wondered why we needed this separate
definition of inheritance (since it is a continual source of trouble), but I
suspect that changing it would probably cause new troubles (and worse,
incompatibilities).

So I don't think this solution flies by itself. You have to either except
characteristics that are subprograms (predefined or inherited) or figure out if
it is safe to eliminate part or all of 12.5.1(21/3) in favor of the 7.3.1 rules.
Both sound like fun. ;-)

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

From: Steve Baird
Date: Tuesday, July 27, 2010  6:49 PM

> Humm, "characteristics" include inherited subprograms (3.4(17/2)).

Good catch.

>
> So I don't think this solution flies by itself. You have to either
> except characteristics that are subprograms (predefined or inherited)
> or figure out if it is safe to eliminate part or all of 12.5.1(21/3)
> in favor of the 7.3.1 rules. Both sound like fun. ;-)
>

Can we accomplish your first alternative by tweaking my earlier alternative #1
so that we have

   !wording

   Replace 12.5.1(20/2)
      If the ancestor type is a composite type that is not an array type,
      the formal type inherits components from the ancestor type
      (including discriminants if a new discriminant_part is not
      specified), as for a derived type defined by a
      derived_type_definition (see 3.4 and 7.3.1).

   with something like

      Except for inherited primitive subprograms, the
      characteristics of a formal derived type are defined
      as for a derived type defined by a derived_type_definition
      (see 3.4 and 7.3.1).

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

From: Tucker Taft
Date: Tuesday, July 27, 2010  7:55 PM

[I am lassoing Bob into this discussion as well...]

Why not eliminate the first part of 12.5.1(21/3):

   For a formal derived type, the predefined
   operators and inherited user-defined subprograms
   are determined by the ancestor type and any
   progenitor types, and are implicitly declared
   at the earliest place, if any, immediately within
   the declarative region in which the formal type
   is declared, where the corresponding primitive
   subprogram of the ancestor or progenitor is
   visible (see 7.3.1).

This seems to be (almost) perfectly redundant with the wording of 7.3.1(6/3):

   For a derived_type_definition, each inherited
   primitive subprogram is implicitly declared at the
   earliest place, if any, immediately within the
   declarative region in which the type_declaration
   occurs, but after the type_declaration, where the
   corresponding declaration from the parent is visible.

Clearly ancestor has to be thought of as the "parent"
in 7.3.1, but I suspect the progenitor part is missing, from 7.3.1 and will need
to be added, since can't an interface have a private null operation?

In any case, if we are making a change here, it would be nice to try to
eliminate this redundancy.

I suspect the reason we didn't do this before was that the term "characteristic"
was not treated as a formal notion early in the Ada 95 process.  Interestingly,
the use of the term "characteristic" in 3.4 is *not* marked as a definition, but
perhaps it should be. I think when it was written, it was treating
"characteristic" as an informal term.

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

From: Randy Brukardt
Date: Wednesday, July 28, 2010  1:03 AM

> [I am lassoing Bob into this discussion as well...]

Good, too complex to do alone: we need the big guns.

...
> Clearly ancestor has to be thought of as the "parent"
> in 7.3.1, but I suspect the progenitor part is missing, from
> 7.3.1 and will need to be added, since can't an interface have a
> private null operation?

I suspect that progenitor wasn't mentioned because they can't be hidden (neither
the interface nor the operations can be in the private part). So the inherited
operations are always available. But if this is describing the normal case as
well (too lazy to look it up right now: the office air conditioner is broken and
it is 85 in here and rising...) then maybe it needs to be added because surely
operations (both null and abstract) can be inherited only from a progenitor.

> In any case, if we are making a change here, it would be nice to try
> to eliminate this redundancy.

True.

> I suspect the reason we didn't do this before was that the term
> "characteristic" was not treated as a formal notion early in the Ada
> 95 process.  Interestingly, the use of the term "characteristic" in
> 3.4 is *not* marked as a definition, but perhaps it should be.
> I think when it was written, it was treating "characteristic"
> as an informal term.

For some bizarre reason, the term is defined in 7.3(15). Since that hasn't been
changed since the Ada 95 days, only you guys might be able to explain that! I
agree that it ought to be defined and indexed in 3.4(7) as well, since that is
where the nice list of characteristics is given. Probably should do that in this
AI (it will require an AI change, since we need to italicize the term).

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

From: Bob Duff
Date: Wednesday, July 28, 2010  8:12 AM

> [I am lassoing Bob into this discussion as well...]

OK.  Apparently I missed the point of this discussion (what problem is being
solved), but I'll give my $0.02.

> Why not eliminate the first part of 12.5.1(21/3):
>
>    For a formal derived type, the predefined
>    operators and inherited user-defined subprograms
>    are determined by the ancestor type and any
>    progenitor types, and are implicitly declared
>    at the earliest place, if any, immediately within
>    the declarative region in which the formal type
>    is declared, where the corresponding primitive
>    subprogram of the ancestor or progenitor is
>    visible (see 7.3.1).
>
> This seems to be (almost) perfectly redundant with the wording of
> 7.3.1(6/3):
>
>    For a derived_type_definition, each inherited
>    primitive subprogram is implicitly declared at the
>    earliest place, if any, immediately within the
>    declarative region in which the type_declaration
>    occurs, but after the type_declaration, where the
>    corresponding declaration from the parent is visible.
>
> Clearly ancestor has to be thought of as the "parent"
> in 7.3.1, but I suspect the progenitor part is missing, from 7.3.1 and
> will need to be added, since can't an interface have a private null
> operation?

Yes, an interface can have a private null procedure.
I agree the progenitor part should be added.

But if you eliminate 12.5.1(21/3), then doesn't 7.3.1(6/3) need to say "generic"
somehow?

> In any case, if we are making a change here, it would be nice to try
> to eliminate this redundancy.
>
> I suspect the reason we didn't do this before was that the term
> "characteristic" was not treated as a formal notion early in the Ada
> 95 process.

I think it was by me.  I think you wrote chap 3, treating "characteristic"
informally, and I wrote chaps 7 and 12, treating it formally, which is why it's
italicized and indexed in chap 7.  I guess we didn't notice the discrepancy
between the two.  My memory is somewhat hazy, but I think I intended
"characteristic" NOT to include primtive subprograms.

>...Interestingly,
> the use of the term "characteristic" in 3.4 is *not*  marked as a
>definition, but perhaps it should be.
> I think when it was written, it was treating  "characteristic" as an
>informal term.

Yes, probably.

Randy Brukardt wrote:

> I suspect that progenitor wasn't mentioned because they can't be
> hidden (neither the interface nor the operations can be in the private part).

The operations can, if they are null.

>... So
> the inherited operations are always available. But if this is
>describing the  normal case as well (too lazy to look it up right now:
>the office air  conditioner is broken and it is 85 in here and
>rising...)

Sounds like nice weather.  If you want sympathy from me, tell me next February
that your heat isn't working.  ;-)

> For some bizarre reason, the term is defined in 7.3(15). Since that
> hasn't been changed since the Ada 95 days, only you guys might be able
> to explain that!

Probably because that's where it was in Ada 83, and I was trying to clarify this
business of "later revealed" characteristics, which was confusing in Ada 83.  I
somehow missed that the term was also being used (slightly differently) in 3.4.

>...I agree that it ought to be defined and indexed in 3.4(7) as well,
>since that is where the nice list of characteristics is given. Probably
>should do that in this AI (it will require an AI change, since we need
>to  italicize the term).

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

From: Steve Baird
Date: Wednesday, July 28, 2010  7:37 PM

The following is my attempt to incorporate everyone's helpful feedback.
Thanks all.

   !wording

   Replace 12.5.1(20/2)
      If the ancestor type is a composite type that is not an array type,
      the formal type inherits components from the ancestor type
      (including discriminants if a new discriminant_part is not
      specified), as for a derived type defined by a
      derived_type_definition (see 3.4 and 7.3.1).

   with

      The characteristics of a formal derived type are defined
      as for a derived type defined by a derived_type_definition
      (see 3.4 and 7.3.1).

      AARM note:
      Note that this includes the implicit declarations of inherited
      primitive subprograms.


   Replace the beginning of 12.5.1 (21/3)

     For a formal derived type, the predefined operators and inherited
     user-defined subprograms are determined by the ancestor type and any
     progenitor types, and are implicitly declared at the earliest place,
     if any, immediately within the declarative region in which within
     the immediate scope of the formal type is declared, where the
     corresponding primitive subprogram of the ancestor or progenitor is
     visible (see 7.3.1). In an instance, the copy of such an implicit
     declaration declares ...

   with

     In an instance, the copy of an implicit declaration of an
     inherited primitive subprogram of a formal derived type declares ...

======


Comments?


The idea is that we are not changing the language definition at all with respect
to primitive subprograms. The new definition is intended to be equivalent to the
old (just as it is equivalent with respect to another characteristic,
components).

Bob wrote:
> But if you eliminate 12.5.1(21/3), then doesn't 7.3.1(6/3) need to say
> "generic" somehow?

I think the answer is "no", 7.3.1 says how to do it for a
derived_type_definition. Then later, we say (in 12.5.1) "and it works the same
way for formal derived types". In particular, note that the new wording in
12.5.1 says "(see .. and 7.3.1)".

I also don't see any need to add any wording about progenitors.
It seems like that is handled in 3.4.

Bob wrote:
> My memory is somewhat hazy, but I think I intended "characteristic"
> NOT to include primitive subprograms.

That would make more sense to me. Characteristics other than primitive
subprograms are not declared and there is no need to worry about the point at
which they are declared. By including primitive subprograms we introduce that
concern.

It is appealing to argue that "if I know that A is derived from B and that B is
an array type, then I should know that A is an array type". As Bob knows, this
model is at least close to implementable (at least for Ada95) because Bob worked
on converting the Rational compiler away from this incorrect model.

On the other hand, I would concede that this model would introduce lots of
corner cases that would need to be dealt with and that making a change along
these lines at this point would be a terrible idea.

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


Questions? Ask the ACAA Technical Agent