Version 1.7 of ais/ai-00228.txt

Unformatted version of ais/ai-00228.txt version 1.7
Other versions for file ais/ai-00228.txt

!standard 3.09.3 (6)          03-02-20 AI95-00228/04
!standard 8.05.4 (5/1)
!class binding interpretation 03-01-07
!status Amendment 200Y 03-02-20
!status ARG Approved 8-0-0 03-02-09
!status work item 02-01-23
!status received 00-04-10
!priority Low
!difficulty Medium
!qualifier Clarification
!subject Premature use of 'shall be overridden' subprograms
!summary
A subprogram which 'shall be overridden' in the sense of 3.9.3(6) is not subject to the restrictions that apply to an abstract subprogram. It is illegal to rename a 'shall be overridden' subprogram.
!question
AI95-00211 states that "the 'shall be overridden' property of 3.9.3(6) applies to a renamed view. Thus, any renaming of an inherited subprogram that must be overridden is illegal."
It seems that this formulation is incomplete, and that AI95-00211 should have covered some other cases. Consider the following example, derived from the one in the AI:
package Types is type T is tagged null record; function F return T; end Types;
with Types; package Extensions is type E is new Types.T with null record; type A is access function return E; procedure P (X : A := F'access); -- Legal? (Yes.) function F return E; end Extensions;
Between the place where E is declared and the place where F is overridden, there are a number of constructs that could be used to reference F. Are such constructs legal? (Yes.)
!recommendation
(See Summary.)
!wording
(See Corrigendum.)
!discussion
The essence of the question revolves around the difference between 'abstract' and 'shall be overridden'. AI95-00211 seems to have been written with the assumption that these terms were more or less synonymous, but in fact they are not. By definition, an abstract subprogram has no implementation, so we must prevent any construct that could lead to non-dispatching calls to such a subprogram. On the other hand, the rules of 3.9.3(6) ensure that an overrider will be provided for each 'shall be overridden' subprogram, and that this overrider will not be abstract (assuming the type itself is not abstract). So non-dispatching calls to such subprograms are fine, because we can guarantee that there exists a proper implementation.
To illustrate the difference, consider the following example, which is somewhat similar to the one in the question, but shows several levels of derivation:
package P1 is type T1 is tagged ...; function F return T1; end P1;
with P1; package P2 is type T2 is new P1.T1 with ...; -- Inherits an F which shall be overridden. -- May use F'Access in a default expression here. private function F return T2; end P2;
with P2; package P3 is type T3 is new P2.T2 with ...; -- Inherits an F which shall be overridden. -- May use F'Access in a default expression here. function F return T3; end P3;
with P1; package P4 is type T4 is new abstract P1.T1 with ...; -- Inherits an F which is abstract. -- F'Access is illegal. end P4;
In package P2, T2 inherits a function F which shall be overridden. In this instance the overrides appear in the private part, but at the point of the type declaration we know that an override is coming. So in the visible part of P2 it is legal to evaluate the attribute Access for F in a default expression (note that most other usages of F are illegal because they would freeze T2 before its full definition). This wouldn't be true for abstract subprograms.
In package P3, when we derive from P2.T2, P2.F being a function with a controlling result, it has to be overridden. Again, F'Access is legal in a default expression in the specification of P3, even before the declaration of the overrider.
In package P4, T4 is declared to be an abstract type, so the inherited F is abstract. It may or may not be overriden, but it is illegal, say, to evaluate F'Access before a non-abstract override has been given.
A similar example can be constructed with an abstract root type and an inherited procedure:
package P1 is type T1 is abstract tagged ...; procedure P (A : T1) is abstract; end P1;
with P1; package P2 is type T2 is new P1.T1 with ...; -- Inherits a P which shall be overridden. -- May use P'Access in a default expression here. private procedure P (A : T2); end P2;
with P2; package P3 is type T3 is new P2.T2 with ...; -- Inherits a perfectly good P. -- May use P'Access anywhere. end P3;
with P1; package P4 is type T4 is new abstract P1.T1 with ...; -- Inherits a P which is abstract. end P4;
The inheritance mechanisms are similar in this second example, except that the procedure P inherited by P3.T3 does not have the 'shall be overridden' property. That's because the parent type, P2.T2, is guaranteed to have a non-abstract primitive procedure P (even though the overrider for P is declared in the private part).
Based on this analysis, let's look again at AI95-00211. This AI deals with renamings of 'shall be overridden' subprograms, as shown in the following example:
package Types is type T is abstract tagged ...; procedure P (F : T) is abstract; end Types;
with Types; package Extensions is type E is new Types.T with ...; -- Inherits a P which shall be overridden. procedure Pr (F : E) renames P; procedure P (F : E); end Extensions;
Pr denotes a new view of P, and we know that P will ultimately be overridden. The overrider of P will actually provide a body for Pr, too, so there is no need for Pr to inherit the 'shall be overridden' property. However, an odd consequence of this analysis is that, although Pr occurs before the declaration of the override, it is not technically a squirrelling renaming in the sense of AARM 8.5.4(8.g). This seems unnecessarily confusing.
In order to avoid this oddity, it seems appropriate to make the renaming illegal (as stated in AI95-00211) but the logic for reaching that conclusion in AI95-00211 was incorrect, because of the confusion between 'abstract' and 'shall be overridden'.
!corrigendum 8.5.4(5/1)
Insert after the paragraph:
The profile of a renaming-as-body shall be subtype-conformant with that of the renamed callable entity, and shall conform fully to that of the declaration it completes. If the renaming-as-body completes that declaration before the subprogram it declares is frozen, the profile shall be mode-conformant with that of the renamed callable entity and the subprogram it declares takes its convention from the renamed subprogram; otherwise, the profile shall be subtype-conformant with that of the renamed callable entity and the convention of the renamed subprogram shall not be Intrinsic. A renaming-as-body is illegal if the declaration occurs before the subprogram whose declaration it completes is frozen, and the renaming renames the subprogram itself, through one or more subprogram renaming declarations, none of whose subprograms has been frozen.
the new paragraph:
If the callable_entity_name of a renaming denotes a subprogram which shall be overridden (see 3.9.3), then the renaming is illegal.
!ACATS test
A B-Test should be created to test these rules, possibly added to an existing test.
!appendix

From: Pascal Leroy
Sent: Friday, April 07, 2000 3:16 AM

I am trying to implement AI95-00211 (now that we have ACATS tests for AIs ;-)
and it seems to me that there is one case missing from this AI.

The interesting part of AI95-00211 is this:

"Can a subprogram which must be overridden in the sense of 3.9.3(6) be renamed?
(No.)"

The referenced paragraph, 3.9.3(6), states that:

"For a derived type, if the parent or ancestor type has an abstract primitive
subprogram, or a primitive function with a controlling result, then ... the
subprogram shall be overridden with a nonabstract subprogram..."

It seems to me that AI95-00211 should also forbid the use of such a subprogram
as the prefix of attributes 'Access and 'Unchecked_Access.  Here is an example,
derived from the one in the AI, which shows that you can use 'Access to squirrel
away one of these "must be overridden subprogram":

package Types is
    type T is tagged null record;
    function F return T;
end Types;

with Types;
package Extensions is
    type E is new Types.T with null record;
    type A is access function return E;
    X : A := F'Access; -- Legal? Hopefully not!
    function F return E;
end Extensions;

Note that an abstract subprogram cannot be used as the prefix of 'Access
(3.9.3(11)) but this doesn't help because these "must be overridden" subprograms
are not abstract.

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

From: Tucker Taft
Sent: Friday, April 07, 2000 7:44 AM

Pascal Leroy wrote:
> ...
> It seems to me that AI95-00211 should also forbid the use of such a subprogram
> as the prefix of attributes 'Access and 'Unchecked_Access.

And 'Address, and presumably any attribute.

Probably the simplest thing would be to say that the implicitly declared
(inherited) function is abstract.  Why didn't we say that?  Then presumably you
*could* rename them, and you would just get an abstract function.

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

From: Pascal Leroy
Sent: Friday, April 07, 2000 7:56 AM

> Probably the simplest thing would be to say that the implicitly declared (inherited)
> function is abstract.  Why didn't we say that?  Then presumably you *could* rename
> them, and you would just get an abstract function.

That crossed my mind, but I don't think it works.  Consider:

    package P1 is
        type T1 is abstract tagged null record;
        procedure P (X : T1) is abstract;
    end P1;

    with P1;
    package P2 is
        type T2 is new P1.T1 with null record;
    private
        procedure P (X : T2);
    end P2;

    with P2;
    package P3 is
        type T3 is new P2.T2 with null record;
    end P3;

If you say that P2.T2 inherits an abstract P which is later overridden by the
declaration in the private part, then presumably P3.T3 also inherits an abstract
P, which then would have to be overridden.  This is substantially different from
what 3.9.3(6) is currently saying.  These "must be overridden" subprograms are
very weird.

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

From: Tucker Taft
Sent: Friday, April 07, 2000 2:21 PM

There are no functions in your example.  What exactly are you
trying to illustrate?  Can you try to be more explicit?
In general, we know that a non-abstract type has no abstract
primitives, even if the non-abstract ones are declared in the private part.
The same would hold true for functions with a controlling result,
though it wouldn't be as interesting, since they always become
abstract again, even if they are overridden with a non-abstract
function.  Making the inherited function abstract seems to
simplify the description to me, so I guess you need to explain
the problem again.

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

From: Pascal Leroy
Sent: Monday, April 10, 2000 5:10 AM
> In general, we know that a non-abstract type has no abstract
> primitives, even if the non-abstract ones are declared in the private part.

Good point.  I withdraw my objection.

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

To: Randy Brukardt
Sent: Monday, April 10, 2000 6:12 PM

> Probably the simplest thing would be to say that the implicitly declared
> (inherited) function is abstract.  Why didn't we say that?  Then presumably
> you *could* rename them, and you would just get an abstract function.

I agree here with Pascal(1) (and not Pascal(2)!) -- I don't think this works.

This rule appeared very late in the game; it appears to have been added to
RM9X;5.0 (it isn't in 4.0). Prior to that, these things *were* abstract. I would
be very cautious about trying to resurrect a rule that didn't work then.

The point of this rule is to insure that a non-abstract tagged type has no
abstract operations. (Tucker claims this as a statement of fact, but it is in
fact this rule (3.9.3(6)) that guarentees that property; any change to this rule
may very well void that property.)

You could, of course, make 3.9.3(5) true for all types, then add a "must be
overridden" rule for any abstract operation of a non-abstract, tagged type.
Since that is the obvious way to get from RM9X;4.0 to the current rules, I have
to think that it doesn't work for some reason.

It is important to note that you *can* rename a "must be overridden" subprogram,
the issue is that the resulting subprogram still needs to be overridden (so it
is illegal for that reason). (And trying to override it causes illegal
homographs, so it cannot be made legal.) Changing the subprograms to be
"abstract" doesn't change this at all.

---

The interesting question is whether there is a real problem here at all. A
renaming is illegal because the needed overridding can't be given. There is no
such problem with attributes (nor with generic actual subprograms, the other
case covered in 3.9.3(11), which also should be covered by any rule coming out
of this discussion). We know that there must be a concrete subprogram at some
point (because of the "must be overridden" rule). Using it as the prefix to an
attribute might annoy a [mostly] one-pass compiler, but I don't see how that is
different than using a subprogram whose body hasn't been seen yet.

That is, to extend Pascal's original example:

package Types is
    type T is tagged null record;
    function F return T;
end Types;

with Types;
package Extensions is
    type E is new Types.T with null record;
    type A is access function return E;
    function F2 return E;
    Y : A := F2'Access; -- Legal? Of course.
    X : A := F'Access; -- Legal? Why not?
    function F return E; -- (1).
end Extensions;


The use of F2 in 'Access is legal. So why shouldn't the use of F in 'Access be
legal? We know that the overridding at (1) exists; otherwise the unit Extensions
is illegal anyway. And assuming the the overridding exists, how is this
different than F2? I can't find any reason.

Have I missed something?

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

From: Pascal Leroy
Sent: Tuesday, April 11, 2000 3:46 AM

Well, there are two problems here.

The first problem is that surely the implicit F (the one that must be
overridden) and the explicit F (the one that overrides) are different
subprograms (otherwise we wouldn't be talking about overriding, right?).  Now we
have this rule that "two access-to-subprogram values are unequal if they
designate different subprograms" (4.5.2(13)).  Your proposal violates this rule,
because you are saying that the 'Access attribute will return the same value for
both Fs.  That's distinctly ugly.

The second problem is more serious, and that's what got me started.  Once you
have built an access-to-subprogram value that designates one of these
must-be-overridden subprograms, you can use it in a renaming, as in:

    X : A := F'Access; -- Legal? Randy says yes.
    function G return E renames X.all; -- Legal?  Randy is busy trying to solve the halting problem.
    function F return E;

Now the interesting question is: is G one of these must-be-overridden
subprograms?  Because the subprogram name is dynamic, you have no way to tell.
But of course, this directly affects the legality of the program, because you
have to either accept or reject the renaming.  (Now you should see the
relationship with AI 211.)

Note that abstract-ness is another property that (1) influences legality and (2)
propagates through renamings, but in the case of abstract subprograms we know
that a dynamic name cannot designate an abstract subprogram (3.9.3(11)) so we
know that the function G above is never abstract.  That's why I believe that the
only option is to make 'Access illegal for these must-be-overridden subprograms.

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

From: Randy Brukardt
Sent: Tuesday, April 11, 2000 12:08 PM


> Well, there are two problems here.
>
> The first problem is that surely the implicit F (the one that
> must be overridden) and the explicit F (the one that
> overrides) are different subprograms (otherwise we wouldn't
> be talking about overriding, right?).  Now we have this rule
> that "two access-to-subprogram values are unequal if they
> designate different subprograms" (4.5.2(13)).  Your proposal
> violates this rule, because you are saying that the 'Access
> attribute will return the same value for both Fs.  That's
> distinctly ugly.

Well, I'm saying that F'Access designates the concrete subprogram. So of course
it would have the same value. This is the same subprogram that a call to F would
execute. I don't find this weird; tagged types (which these must be) already
have that semantics for calls of subprograms overridden in the private part. So
I'm not suggesting anything new here.

> The second problem is more serious, and that's what got me
> started.  Once you have built an access-to-subprogram value
> that designates one of these must-be-overridden subprograms,
> you can use it in a renaming, as in:
>
>     X : A := F'Access; -- Legal? Randy says yes.
>     function G return E renames X.all; -- Legal?  Randy is
> busy trying to solve the halting problem.
>     function F return E;
>
> Now the interesting question is: is G one of these
> must-be-overridden subprograms?  Because the subprogram name
> is dynamic, you have no way to tell.  But of course, this
> directly affects the legality of the program, because you
> have to either accept or reject the renaming.  (Now you
> should see the relationship with AI 211.)

No, I don't actually see any relationship with AI 211; I don't agree with any of
this. The properties of G come from the "designated subprogram" of A, which
certainly is not a "must be renamed" entity. So G is always legal, and certainly
does not require any overriding. That is true for any renaming, I don't know why
you think that it ought to be different for this case.

Any such property is "lost" when the 'Access is taken. And clearly a 'Access can
only refer to a "concrete" subprogram - it either refers to the overriding
subprogram or it has to be illegal somehow. Since there is no support in the RM
for the latter, I was suggesting that the former was intended.

> Note that abstract-ness is another property that (1)
> influences legality and (2) propagates through renamings, but
> in the case of abstract subprograms we know that a dynamic
> name cannot designate an abstract subprogram (3.9.3(11)) so
> we know that the function G above is never abstract.  That's
> why I believe that the only option is to make 'Access illegal
> for these must-be-overridden subprograms.

Well, I don't agree that F'Access references the "must-be-overridden"
subprogram. Certainly a call to F references the concrete routine (put this
before the declaration of F2 in the example, assume a default initialized object
of it in the body of Extensions):

    type Rec is record
       Comp : E := F; -- Must reference the concrete routine,
                      -- not the "must-be-overridden" one.
    end record;

So why should 'Access be different?


In all honesty, I really don't care about this issue that much. I was just
trying to figure out why the manual was the way it was. Since RM9X;4.0 has
pretty much the semantics that Tucker is suggesting, I was trying to figure out
why it was changed, and in particular, why it was changed away from simply
requiring overriding of any inherited abstract routines. I have to assume that
there was some important reason for this change, so changing it back is
something we should not do without knowing the reasons for the initial change.

A shakier assumption is that the issues of premature use was considered when the
change was made. It seems hard to believe that an entire new concept was
introduced without any consideration of uses of the subprograms. Thus, I find
that there must have been an intent that these things work -- I'm just trying to
figure out what they mean. And it turns out that that meaning is not
inconsistent with the rest of the language.

I know that is a shaky argument (as arguments from intent usually are).
Hopefully, Bob or Tucker will help out here.

In any case, I am not adverse to adding 3.9.3(11) language to
"must-be-overridden" subprograms. "Before the subprogram is overridden, the
subprogram may not be used as a generic actual subprogram or as the prefix of an
attribute reference for the Access, Unchecked_Access, or Address attributes."
(But, does this cause problems for generic formal types, where the subprogram is
not required to be overridden until instantiation??) But I don't think it is
strictly necessary to have a consistent semantics.

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

From: Pascal Leroy
Sent: Tuesday, April 11, 2000 3:30 PM

> No, I don't actually see any relationship with AI 211; I don't agree with
> any of this. The properties of G come from the "designated subprogram" of A,
> which certainly is not a "must be renamed" entity. So G is always legal, and
> certainly does not require any overriding. That is true for any renaming, I
> don't know why you think that it ought to be different for this case.

So you are telling me that the following ought to be legal:

     X : A := F'Access;
     function G return E renames X.all;
     function F return E;

but obviously AI 211 says that the following is illegal:

     function G return E renames F;
     function F return E;

so much for consistent language design!  If your program is rejected because
of AI 211, just add an extra access-to-subprogram variable, it makes it
legal (and so much more readable).

> Well, I don't agree that F'Access references the "must-be-overridden"
> subprogram. Certainly a call to F references the concrete routine (put this
> before the declaration of F2 in the example, assume a default initialized
> object of it in the body of Extensions):
>
>     type Rec is record
>        Comp : E := F; -- Must reference the concrete routine,
>                       -- not the "must-be-overridden" one.
>     end record;
>
> So why should 'Access be different?

I don't care about dynamic semantics, I am talking name resolution and
legality rules.  In the above expression, the name F designates the
subprogram that will be overridden; it happens that at execution you call
the overriding one, but in this language we try to precisely define the
meaning of a name as opposed to what happens at execution.

If you say that the name F in F'Access references the overriding subprogram,
you are introducing a case where a name references an entity which has not
been declared yet.  This is something entirely new, and it's going to break
more that one compiler (for no good reason).

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

From: Randy Brukardt
Sent: Tuesday, April 11, 2000 6:44 PM

> I don't care about dynamic semantics, I am talking name resolution and
> legality rules.

But it is only the dynamic semantics that matters. There is no name resolution
or legality problem here.

> In the above expression, the name F designates the
> subprogram that will be overridden; it happens that at execution you call
> the overriding one, but in this language we try to precisely define the
> meaning of a name as opposed to what happens at execution.
> If you say that the name F in F'Access references the overriding subprogram,
> you are introducing a case where a name references an entity which has not
> been declared yet.  This is something entirely new, and it's going to break
> more that one compiler (for no good reason).

That is not what I meant at all. I said that F'Access returns the overriding
subprogram -- I suppose that is the dynamic semantics. F is the
must-be-overridden subprogram - that is the name resolution. That is precisely
the meaning of a call to F (as I demonstrated earlier) -- why should F'Access
not be usable when a call is?

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

From the minutes of the Cupertino ARG meeting (February 2002):

Pascal explains the current version of the AI. We could reintroduce the notion
of these being abstract, but that was the way it was in draft 4 of Ada 95, and
it was changed for draft 5. So he introduced the notion of "insubstantial" to
handle this.

A long discussion about the meaning of abstract and "must be overridden"
ensues. After several false starts, we look at the following example:

    package P1 is
        type T1 is abstract tagged ...
        function F return T1;
        procedure P (A : T1) is abstract;
    end P1;

    with P1;
    package P2 is
        type T2 is new P1.T1 ...
        -- Is P'access allowed here?? [Yes.]
    private
        function F return T2;
        procedure P (A : T2);
    end P2;

    with P2;
    package P3 is
        type T3 is new P2.T2 ... -- Legal (P is not abstract)
        function F return T3;
    end P3;

    with P1;
    package P4 is
        type T2 is new abstract P1.T1 ...
        -- P'Access is not allowed.
    end P4;

If the parent type has an abstract procedure, the inherited procedure is "must
be overridden", but not abstract, so we can do anything with the inherited
subprogram, and don't have to override it again when deriving from the derived
type. The function case works the same, except that it is "must be overridden"
when deriving from the derived type.

Bob Duff explains that "we" (the MRT) defined this so that if you "know a real
definition is coming", you can take advantage of it (that is, the abstract
restrictions do not apply to it). So it is intentional that you can use these
as if they are normally defined, because they must be before the end of a
scope. This is the reason that "must be overridden" items are not defined to be
abstract.

Someone asks if P'Access freezes P? No, it could be in a default expression.

Pascal expresses concern about name resolution, but is convinced that a call
from outside would need to use the real body, so this should work. Pascal will
make sure that AI-211 does not conflict.

Tucker says that this AI is a tempest in teapot. He suggests that it should be
a confirmation. Pascal says that we finally understand what these paragraphs
mean.

Pascal will rewrite the AI.

Approve intent of the AI: 7-0-0

[Editor's note: this is complete reversal from earlier discussions.]

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

From the minutes of the Bedford ARG meeting (October 2002):

[Various typos omitted - ED]

Tucker: How does freezing apply here? In the example which has P'Access, P is
frozen, so it can't be overridden. It would have to be a default expression.
Pascal wants to know where this rule is. After much argument, 13.14(4/1) is
pointed out.

There is some discussion about what compilers currently do with these examples.
Through the wonders of modern technology (the laptop), several people try this
example on their favorite compiler. Gary reports GNAT says: "prefix must be
abstract". Tucker says that AdaMagic complains about freezing; as a default
expression, it works; the squirreling rename says "fatal internal memory access
error"!

The example in the question is wrong, it should not have "abstract" in package
Types. It would be useful to distinguish between the function example (non
abstract type) and the procedure example (abstract type).

The examples are screwed up, so the AI is sent back to Pascal to fix them.

We discussed squirreling renames, and some members of the group are
uncomfortable with the fact that this is not a squirreling rename, but it looks
identical to it. That is different from the normal case. Randy says that he
thinks the conclusion of AI-211 is correct (that the rename is illegal), but
the logic to get to that conclusion is wrong. We probably need a binding
interpretation to fix this.

The group concludes that the best solution is to make these illegal. That
should be done by inserting a new rule after 8.5.4(5): "if the
callable_entity_name of a renaming is a must-be-overridden subprogram, then the
renaming is illegal".

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


Questions? Ask the ACAA Technical Agent