Version 1.5 of ais/ai-10218.txt

Unformatted version of ais/ai-10218.txt version 1.5
Other versions for file ais/ai-10218.txt

!standard 8.3(26)          03-04-28 AI95-00218-02/04
!class amendment 02-09-30
!status work item 02-09-30
!status received 02-09-30
!priority Medium
!difficulty Medium
!subject Accidental overloading when overriding
!summary
In order to reduce problems with overriding of primitive operations, additional syntax for subprogram declarations is introduced. A pragma controls the use of this syntax.
!problem
Subtle bugs result from mistakes in the profile of an overriding subprogram. For example:
with Ada.Finalization; package Root is type Root_Type is new Ada.Finalization.Controlled with null record; procedure Do_Something (Object : in out Root_Type; Data : in Natural); -- (1) procedure Finalize (Object : in out Root_Type);-- (2) end Root;
with Root; package Leaf is type Derived_Type is new Root.Root_Type with null record; procedure Do_Something (Object : in out Derived_Type; Data : in Boolean); -- (3) procedure Finalise (Object : in out Derived_Type); -- (4) -- Note: Alternative spelling of "Finalize". end Leaf;
with Leaf; procedure Sample is Obj : Leaf.Derived_Type; begin Leaf.Do_Something (Obj, 10); -- Calls (1). -- Finalization of Obj will call (2). end Sample;
Assume the programmer intended (3) and (4) to override (1) and (2), but made subtle declaration errors. Because (1) and (3) are not homographs, the declaration of (3) is legal. However, (3) does not override (1) as intended. Therefore, the call in Sample calls the wrong routine. Similarly, the incorrect declaration of "Finalise" (4) does not override (2). Thus, the finalization of Sample.Obj will call the wrong routine.
The resulting bugs are very difficult to find, especially because the programmer will probably look at this call several times before even thinking that the wrong routine might be called. The bug is even harder to find when the call is dispatching or implicit (as it is for Finalize), because the reason that the wrong routine is being called is not obvious. In the Finalize case, the programmer might even think that the compiler is failing to call Finalize at all. These problems have generated many "bug" reports to compiler writers, including ones from their own development teams.
A more serious problem is that it makes maintenance of object-oriented Ada 95 code much more difficult. Consider a maintenance change to the root class which adds a parameter to Do_Something. All extensions of Root_Type that override Do_Something will now silently overload it instead. The change probably will break all existing code, yet provide no warnings of the problem.
A rarer, but similar problem can occur when a routine accidentally overrides another. In this case, an inappropriate routine may be called via dispatching, and may cause the failure of an abstraction.
All of these cases violate the Ada design principle of least surprise, as described in paragraph 8 of the Introduction to the standard.
!proposal
The problem of accidental overloading rather than overriding can be eliminated if the Ada compiler knows when the programmer wishes to override a routine. Similarly, accidental overriding can be minimized if the Ada compiler knows that the programmer has declared all intentional overriding.
Unfortunately, a complete solution to this problem would be incompatible with existing Ada 95 code. Therefore, we have to introduce a solution which permits backward compatibility and applies fully only when the programmer asks for it.
Thus, we introduce a new pragma, Explicit_Overriding, and additional syntax with a new nonreserved keyword which indicates that overriding will or might occur. Explicit_Overriding is a configuration pragma which requires use of the alternative syntax.
The general idea is that subprogram declarations that are overriding are prefixed with "overriding" whereas subprogram declarations without this new syntax must not override another routine. The same applies to renamings and generic instantiations. Special situations arise with generic packages and with private types.
In the case of generics with a formal type it is possible that whether a declaration in the generic specification is overriding or not depends upon the actual type. In order to avoid imposing additional contract requirements such declarations may be prefixed by "overriding or not" in which case no check is made.
The form "overriding or not" may in fact be used in all circumstances and has the effect of turning off the checking for that declaration.
In the case of a subprogram which is a visible operation of a private type (or private extension), checking may occur twice, once for the partial view and again for the full view. It might be that the operation is not visibly overloaded but turns out to be overloaded when the full type declaration occurs. In this case the operation in the partial view is not prefixed by "overriding" but an overriding clause has to be given in the private part which consists essentially of a copy of the specification prefixed by "overriding" (or even "overriding or not"). This overriding clause has to have full conformance with the specification in the partial view and since such conformance is not defined for generic instances, the partial view may not be an instance.
Note that if a declaration is prefixed by "overriding" then an appropriate check is always made (even in the absence of the pragma Explicit_Overriding) since it would be confusing for such explicit syntax to be ignored.
!wording
In 2.9(3) as modified by AI 284 add the following to the list of nonreserved keywords
overriding
Change the syntax in 6.1 to read
overriding_indicator ::= overriding [or not] subprogram_declaration ::= [overriding_indicator] subprogram_specification ; abstract_subprogram_declaration ::= [overriding_indicator] subprogram_specification is abstract; overriding_clause ::= overriding_indicator subprogram_specification ;
Add to 8.3 after paragraph 23:
If an explicit declaration of a visible operation of a private type or a private extension by a subprogram_declaration, abstract_subprogram_declaration, or subprogram_renaming_declaration does not include the overriding_indicator "overriding" then it is permitted to give an overriding_clause for the operation in the corresponding private part.
Such an overriding_clause shall occur following the corresponding full_type_declaration and before the type is frozen. Its profile shall be fully conformant with the profile of the subprogram_declaration, abstract_subprogram_declaration or subprogram_renaming_declaration.
Add to 8.3 after paragraph 26:
If an explicit declaration of a visible operation of a private type or private extension by a subprogram_declaration, abstract_subprogram_declaration, subprogram_renaming_declaration or generic_instantiation of a subprogram has the overriding_indicator "overriding" then it shall be an overriding declaration for the partial view of the type. If an overriding_clause has the overriding indicator "overriding" then the corresponding operation shall be an overriding operation for the full view of the type.
If an explicit declaration of an operation of a type which is neither a private type nor a private extension by a subprogram_declaration, abstract_subprogram_declaration, subprogram_renaming_declaration or generic_instantiation of a subprogram has the overriding_indicator "overriding" then it shall be an overriding declaration for the type.
The form of a pragma Explicit_Overriding is as follows:
pragma Explicit_Overriding;
Pragma Explicit_Overriding is a configuration pragma.
The configuration pragma Explicit_Overriding applies to all declarations within compilation units to which it applies, except that in an instance of a generic unit, Explicit_Overriding applies if and only if it applies to the generic unit.
At a place where a pragma Explicit_Overriding applies, an explicit subprogram_declaration, abstract_subprogram_declaration, subprogram_renaming_declaration or generic_instantiation of a subprogram without an overriding_indicator shall not be an overriding declaration for the view of the type at that place. Moreover, unless such a declaration of an operation of a private type given in the visible part has a corresponding overriding clause in the private part then it shall not be an overriding declaration for the full view of the type. In addition to the places where Legality Rules normally apply, these rules also apply in the private part of an instance of a generic unit.
AARM Note: The overriding required by these rules does not necessarily need to happen immediately at the declaration of a primitive operation. It could occur later because of a later implicit declaration in the declarative region (see 7.3.1).
Change the syntax in 8.5.4 to read
subprogram_renaming_declaration ::= [overriding_indicator] subprogram_specification renames callable_entity_name;
Change the syntax in 12.3 to read
generic_instantiation ::= package defining_program_unit_name is new generic_package_name [generic_actual_part]; | [overriding_indicator] procedure defining_program_unit_name is new generic_procedure_name [generic_actual_part]; | [overriding_indicator] function defining_designator is new generic_function_name [generic_actual_part];
!example
Here is our original example using the new pragma and syntax.
pragma Explicit_Overriding;
with Root; package Leaf is type Derived_Type is new Root.Root_Type with null record; overriding procedure Do_Something (Object : in out Root_Type; Data : in Boolean); -- Error: overriding procedure Finalise (Object : in out Root_Type); -- Error: -- Note: Alternative spelling of "Finalize". end Leaf;
The declarations of Do_Something and Finalise will now cause errors. The problem will immediately be pointed out to the programmer.
!discussion
The configuration pragma Explicit_Overriding is necessary for backward compatibility. If the pragma is applied then the prefix "overriding" is required on all subprogram declarations that do override. This checking prevents accidental overriding. Similarly if the pragma is applied then any subprogram declaration which does not override must not have the prefix.
If the pragma is not applied and the prefix is omitted then there is no check that the subprogram does not override. However, if the prefix is given then even in the absence of the pragma, a check is still made that the subprogram does override. This provides maximum benefit with backward compatibility. The possibility of simply using the pragma to disable all overriding checks was considered but dismissed on the grounds that it would be very surprising for the programmer to be able to write "overriding" and then for the compiler to ignore it.
The form "overriding or not" is required so that we can handle generic units where we cannot tell for sure whether overriding occurs. For instance, a mix-in generic does not care whether its operations override existing ones (the user of the generic may care, but that cannot be specified as part of the generic). Therefore, we provide "overriding or not" as a "don't care" marker, so that projects can still use the pragma Explicit_Overriding even if such generics are included. The effect of "overriding or not" can be thought of as restoring the Ada 95 rules for overriding for a particular declaration.
Note that the forms "overriding" and "overriding or not" are part of a subprogram declaration and not the subprogram specification. This is because we do not want them to be permitted in all syntactic situations which use subprogram specification such as generic subprogram declarations, formal subprogram parameters and subprogram body stubs. However, we do want them to apply to abstract subprograms, to renaming and to generic instantiations. For example
overriding procedure Op(X: T) is abstract;
overriding procedure Pop(Y: TT) renames Pip;
overriding procedure Pup is new Pap(P1 => A1, P2 => A2);
Observe that we cannot use an overriding indicator with a subprogram body given alone but must supply a distinct subprogram declaration if we need to include one. Recall that in Ada 95, a subprogram body given alone in a package body can override an inherited primitive operation although it cannot be a new primitive operation. It would be surprising to permit the overriding indicator with such a body given alone since the existence of the overriding would not then be clear just from the package specification. This applies to both tagged and untagged types.
Requiring the explicit declaration of overriding is used in some other programming languages, most notably Eiffel (which uses the keyword redefine). Other commonly used languages (including Java and C++) also have the same problem, but do not have the tradition of safety that Ada has.
This additional checking still could allow an error to occur. The problem could still occur if there existed two or more overloaded inherited routines, and the user overrode the wrong one. However, this would be extremely rare, as it is normally the case that all of the inherited routines with a single name are overridden as a group.
Subtle situations occur with generics and private types. We will consider generics first.
The pragma Explicit_Overriding and the "overriding" syntax are checked in a generic_declaration (as well as in instantiations). Consider
generic type GT is tagged private; package Gen is type DGT is new GT with private; overriding procedure Op (Z : DGT); -- Error: Doesn't override anything. private -- ... end Gen;
If we didn't enforce the rule in generic_declarations (but only in instantiations), we could give "overriding" in this generic as shown. The effect would be to force all actual types for GT to have an operation Op. This would effectively modify the contract of the generic to include that operation.
Of course, we could have said that the overriding checks are not applied in generic declarations so that the user can modify the contract in this way but this would have been at variance with the general language principle of applying all checks in a generic declaration and then checking again as necessary for each instantiation.
As a consequence "overriding" can never be used on operations of a derivation of a generic formal private type (as in the example), as no primitive operations are inherited from the formal type. Thus we write "overriding or not" so that the instantiation can allow overriding. Thus
generic type GT is tagged private; package Gen is type DGT is new GT with private; overriding or not procedure Op (Z : DGT); -- OK: no checking done. -- can be instantiated with a type that -- does or does not already have Op private -- ... end Gen; Observe that if no overriding indicator is given then the contract is changed since an instantiation which does indeed already have Op would be illegal. Thus
generic type GT is tagged private; package Gen is type DGT is new GT with private; procedure Op (Z : DGT); -- No overriding indicator -- cannot be instantiated with a type that -- already has Op private -- ... end Gen;
Note therefore that we can modify the contract to prevent overriding but not to require it.
A related situation is where the formal type is derived so that there may be a number of known primitive operations. Consider
generic type GT is new T with private; package Gen is type DGT is new GT with private; overriding procedure Op (Z : DGT); -- OK if T has Op as an operation. private -- ... end Gen;
If the type T has Op as an operation then we must give an overriding indicator (either "overriding" or "overriding or not"). The form "overriding or not" would be appropriate for the situation where T did not have Op as a primitive but that DT derived from T does have Op and the generic is instantiated with DT.
Note that the only check required at instantiation is to recheck operations which have neither "overriding" nor "overriding or not" to ensure that they do not override some inherited operation. The check in the generic_declaration is sufficient for "overriding", while "overriding or not" needs no check at all.
A somewhat similar situation arises with private types. Thus consider
package P is type T is private; function "+" (Left, Right: T) return T; private type T is range 0 .. 100; -- "+" overrides end P;
as opposed to
package P is type T is private; function "+" (Left, Right: T) return T; private type T is new TT; -- "+" does not override end P;
The point is that the partial view does not reveal whether overriding occurs or not - nor should it since either implementation ought to be acceptable. We should therefore remain silent regarding overriding in the partial view. In order to permit checking when the full circumstances are known, we introduce the possibility of an overriding clause in the private part. This takes the form of an overriding indicator followed by a repetition of the subprogram specification whose profile has to be fully conformant with the profile given in the private view. An overriding clause is only necessary when the operation in the visible part does not have the overriding indicator "overriding" and in the full view the operation does override. Thus
package P is type T is private; function "+" (Left, Right: T) return T; -- overriding not visible private type T is range 0 .. 100; overriding function "+" (Left, Right: T) return T; -- now we know end P;
Any overriding clause must occur before the type is frozen. Note that overriding is always checked for both the partial view and the full view. The form "overriding or not" is permitted for both views. An overriding clause can always be given even if not necessary.
Note that full conformance is required between the profiles although it is not strictly necessary for identification purposes. However, permitting a lesser level might be confusing for the reader. Note moreover that the conformance rules required for overriding are different for tagged and untagged types (tagged require subtype conformance whereas untagged only require type conformance) so it seems a good idea to overkill with full conformance for both.
An overriding clause may not be given in the case where the operation is provided by a generic instantiation. This is because conformance rules are not defined for the profile of an instantiation. There are other restrictions on generic instantiations such as that they are not allowed to complete a subprogram declaration and so this restriction should not seem surprising. As a consequence an instantiation cannot be used to provide an operation in the visible part if that operation turns out to be an overloading one and this is not so for the partial view. This is probably not a frequent situation. The workaround is to give the instantiation a different name and then to rename it as the primitive operation thus
package P is type T is private; procedure Pup is new Pap(P1 => A1, P2 => A2); procedure Op(Y: T) renames Pup;
private type T is new TT; -- TT has an Op and so it overrides overriding procedure Op(Y: T); -- the overriding clause on the renaming end P;
Observe that if the partial view says "overriding" then it would be a burden to require an overriding clause in the full view as well (although it is permitted). However, if the partial view says "overriding or not" then the full view needs to be checked still and thus might require an overriding clause.
Similar examples occur with private extensions
package P is type T is new T1 with private; procedure Foo; private type T is new T2 with ...; overriding procedure Foo; end P;
This covers the situation where T1 does not have the operation Foo but T2 (which of course is ultimately derived from T1) does have the operation.
If T1 does have the operation Foo, then an overriding indicator must be given for the partial view. An overriding indicator can be given for the full view but is not necessary. Thus
package P is type T is new T1 with private; overriding procedure Foo; -- partial view is overriding private type T is new T2 with ...; overriding procedure Foo; -- unnecessary but harmless overriding clause end P;
Implementing the checking of overriding takes some care, because an operation may become overriding at a later point (because of the rules of 7.3.1(6)). A compiler always knows that such overriding will happen later, so this should not provide an implementation burden.
An example of how this could happen:
pragma Explicit_Overriding;
package P is type T is tagged private; private type T is ... procedure Op (Y : T); end P;
package P.C is type NT is new T with null record; overriding procedure Op (Y : NT); -- OK. package Nested is type NNT is new T with null record; procedure Op (Y : NNT); -- Illegal because the body of Nested has -- visibility on primitive 'Op' -- We must add "overriding" -- or "overriding or not". end Nested; private -- P.C.Op overrides P.Op here (P.Op is inherited here). end P.C;
package body P.C is package body Nested is -- P.C.Nested.Op overrides P.Op here (P.Op is inherited here). end Nested; end P.C;
In this situation, the types NT and NNT are not private types and so there is no possibility of an overriding clause. Thus even though at the places where they are declared, the Op of T is not visible nevertheless the eventual overriding has to be mentioned. But we can write "overriding or not" as indicated in the comment to avoid breaking the abstraction (privateness) of the original type P.T.
Contrast this with
package P.C2 is type NT is new T with private; overriding procedure Op (Y : NT); -- Illegal, this doesn't override anything. package Nested is type NNT is new T with private; procedure Op (Y : NNT); -- OK. private type NNT is new T with null record; -- Error: We need an overriding clause for Op here with -- "overriding" or "overriding or not" end Nested; private type NT is new T with null record; -- P.C.Op overrides P.Op here (P.Op is inherited here). -- Thus, we need "overriding procedure Op (Y : NT);" here. end P.C2;
Here the types NT and NNT are private types and so overriding clauses are required.
The configuration pragma Explicit_Overriding does not necessarily apply to the entire partition. It can be given in front of individual units in order to apply only to those units. This allows subsystems which take advantage of the new syntax to be mixed with those that do not.
In a mixed environment, it is important that units be checked based on the environment for which they were designed. Thus, generic instantiations are checked based on whether pragma Explicit_Overriding applies to the generic unit, and not whether it applies to the instantiation.
We considered using further pragmas rather than syntax since syntax was originally considered to be too heavyweight a solution for this problem. However, the introduction of unreserved keywords makes the use of syntax much more attractive than if the words had to be reserved.
An advantage over pragmas is that the syntax is clearly part of the declaration whereas pragmas are not. In the pragma approach the pragmas had to immediately follow the declaration (with optional inclusion of the subprogram identifier) and required special rules for the pragmas to ensure that they only applied to the immediately preceding declaration. The normal rules would have been that the pragma applied to all overloaded declarations with the same identifier which would clearly be inappropriate. There are also dangers if the pragmas get separated from the declaration during program amendment if the identifier is not included and including it seems a burden.
We also considered various other forms of syntax where the indicator followed the details of the subprogram such as
procedure Op(X: T) overrides is abstract;
procedure Pop(Y: TT) overrides renames Pip;
procedure Pup overrides is new Pap(P1 => A1, P2 => A2);
However, it proved difficult to resolve the different grammatical forms and the need to indicate optional overriding as well. Placing the indicator at the front has the merit of being uniform and easily seen by the reader.
The keyword "overriding" seems natural but the somewhat whimsical reuse of existing reserved words in "overriding or not" is perhaps unusual. No better alternative has presented itself and the optional form will not be that frequent. Other possibilities which were rejected included "maybe overriding", "possibly overriding", "overriding optional", and "overriding unknown".
!corrigendum 8.3(26)
To be done.
!appendix

At the Cupertino and Vienna meeting, John Barnes indicated that he would
prefer this AI to use keywords. It was suggested that he prepare an alternative
AI using keywords. (John often wishes that he had kept his mouth shut.)

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

From: Tucker Taft
Sent: Wednesday, Marh 5, 2003  3:55 PM

I notice in the minutes that in cases where you
have to give the overriding clause in the private
part for an operation declared in the visible part,
we run into trouble with defining full conformance
if the overriding declaration involves an instantiation.
It seems easy enough to outlaw that, since we outlaw
it in cases where we allow renaming-as-body, which has
similar conformance problems.

Why not just require that the instantiation have
a new name, and then use an overriding, renaming-as-body
to hook it up to the visibly declared operation?

In Ada 95 we didn't allow instantiations to "complete"
a subprogram declaration both because of the tricky
conformance issues, and because of the possible confusion
in trying to match up an instantiation with a separate
declaration, since the instantiation doesn't have any
explicit parameter profile.  Hence, it would seem just
as reasonable to disallow using instantiations with an
"overriding" prefix under the same circumstances.

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

Editor's note: The following originally was a private discussion between
John Barnes, Pascal Leroy, and me (Randy Brukardt) about a draft of version
4 of this AI. We started discussing a number of deep issues about this
AI, and eventually decided that the discussion should be recorded for
posterity. I've edited out private chit-chat and irrelevancies. And I've kept
the threads together,  which is not necessarily the order that items actually
were discussed. The discussion took place between April 22 and April 26 2003.

---- 1st thread
---- Randy Brukardt

John asked

> The minutes of the last meeting say "Besides, if the syntax
> is given, it is always checked. The configuration pragma
> only changes the checking that occurs when the syntax is not
> used."
>
> Did we really agree this?

Yes.

> I thought that the pragma had to
> be on for the checking to be invoked. That is how the AI
> currently reads. But, clearly we need to permit the syntax
> always and so I suppose we had better check it because it
> would be confusing not to.

Exactly. It would be very strange if "overriding procedure" didn't have to
override something. If the AI doesn't currently say that, its wrong. (Gee, that
was easy. :-)

> And then
>
> 2
>
> Are we going to permit the "optional overriding" indicator
> everywhere or only in those places where it is necessary (in
> generic specs)?  Currently it is permitted everywhere and
> just effectively switches the checking off. But is this
> useful?  Note that "optional overriding" is not the
> syntactic form I intend to propose. I will keep that secret
> for a moment. Note that the summary of the minutes say
> "Don't require maybe overriding on partial view". Maybe they
> should have said "Don't permit maybe overriding on partial
> view".

I don't think that was the intent. Trying to figure out where something should
be (or should not be) allowed seems like a fools game to me. People hate the
places where Ada does that (in out parameters on functions are the prime
example), and I don't think we ought to add more of them absent very good
reasons.

My model of these indicators on the partial view is that they ought to reflect
the reality of the partial view. That is, if "overriding" is given, it better
be a visibly overriding routine. But that may be too much checking and/or too
hard to define, and certainly it is not needed.

In any case, prohibiting "optional overriding" on a partial view wouldn't make
sense (what if that partial view is in a generic spec?? Do you really insist to
repeat the indicator in the private part, even though it just says 'don't
check'??).

In any case, one model of the absence of the configuration pragma is simply
that all subprograms without an indicator have an implicit "optional
overriding". Which only makes sense if you allow it everywhere.

---- Pascal Leroy

I don't quite understand Randy's replies to these questions.  It seems
to me that "optional overriding" should only be allowed in generic
specs, and that it should not be allowed on partial views.  That seems
to be the essence of the discussion as reflected in the minutes and as I
remember it.

---- Randy Brukardt

No, the minutes say "don't REQUIRE "maybe overriding" on the partial view".
That's because John's previous version did require that on the partial view if
you didn't want to break privateness.

I don't think we discussed the notion of restricting "optional overriding" at
the meeting; certainly *I* wasn't discussing that! I was only discussing the
notion of requiring its use in a partial view where you would give the real
overriding or not in the private part.

I see no reason to restrict the use of modifier; that seems like a
methodological restriction best left to style guides, not the language. Where
such things were done in Ada, we've had continuing controversy (see: function
parameter modes, 'in out'). Let's not go there again.

But that's my opinion; I'm certain we've never discussed this topic at the ARG
level (and perhaps we should).

---- Pascal Leroy

I disagree here, but surely this should be discussed during a meeting,
not between the three of us.

Adding "overriding or not" outside a generic has no possible usefulness,
except that of working around the constraints imposed by pragma
Explicit_Overriding.  As a programmer, you are always able to decide if
a declaration is an override or not.  The only case where you would want
to use "overriding or not" is if you are too lazy to determine if a
declaration is an override or not.  I don't think we want to add
language support for laziness.

---- End 1st thread.
---- 2nd thread:
---- John Barnes

I ... found this suggestion from Tucker to get around the
conformance with instantiation problem.

Good idea?

[Editor's note: This is Tucker's mail of March 5, 2003, appended above.]

---- Randy Brukardt

It seems reasonable to me. I don't know if people would complain, but it at
least avoids the hand-waving in the wording.

---- Pascal Leroy

This certainly has the advantage that you don't have to invent complicated
wording to define full conformance with instantiations.

On the other hand, it would make it harder to change existing code to take
advantage of AI 218, as you would have to introduce extra renamings.

I am not sure how often the overrider is an instantiation; although this is
certainly going to depend on the programming style, I suppose that this is
going to be rather infrequent in practice.

Even if we ignore for a moment the complexity of the RM wording for defining
full conformance with an instantiation, I have a hunch that the rules are
going to be sufficiently convoluted that they would lead to obscure errors
and user puzzlement (of course, I would need to see the rules to be sure,
but remember that full conformance in Ada 83 did puzzle many users because
of unnecessarily stringent requirements).

So I guess I am saying that I am slightly in favor of following Tuck's
suggestion.  However, in order to make an informed choice, I would like to
see at least a first-order approximation of the rules for full conformance
with an instantiation (maybe my gut feeling is wrong and they are not that
complicated after all).

---- John Barnes

Of course the other irritating thing with this conformance
business is that overriding of tagged types requires type
conformance whereas that for untagged types only requires
subtype conformance.

But I think we should use full conformance because it will
look very odd if the overriding clause uses different names
for the parameters.

---- End 2nd thread.
---- 3rd thread:
---- John Barnes

Here is a tentative attempt at a rewrite of 218.

---- Randy Brukardt

OK, here goes.

The last paragraph of the !proposal seems awkward, although I think it has the
right meaning. Perhaps "even in the absence of the pragma Explicit_Overriding"
should be put into parens ("always made" certainly includes this) - certainly
it reads a lot better without the "even in..." phrase (but I think its
necessary, since its the point).

8.3(23.1) first sentence says:

  If an explicit declaration of a visible operation of a private type by
  a subprogram_declaration, abstract_subprogram_declaration, subprogram_
  renaming_declaration or generic_instantiation includes an overriding_
  indicator then it is permitted to give an overriding_clause for
  the operation in the corresponding private part.

Shouldn't this say "does not include" instead of "includes"? I don't see any
point to having:
   overriding or not procedure foobar...
 private
   overriding procedure foobar...

8.3(26) first question:

Legality rules only apply in the visible specification of a generic instance
unless the language says otherwise. Here, we clearly want these checks to occur
in the private part as well (it makes no sense to ignore overridding indicators
in generic instantiations). This check is not made in a generic instance body,
so that generic sharing is still possible and that the contract is at least
solely in the generic specification. (Overriding in bodies is rare, anyway).
And the wording is correct.

!discussion, first question.

I'm pretty sure that we don't want to bother with the syntax on bodies for an
obscure case. Indeed, people probably would prefer an error in that case,
because it's unlikely that they actually meant to override anything. I'm not
certain that I believe the explanation (you'll probably tell me that I wrote it
originally); I'd probably just say that the value of supporting this new syntax
on bodies is minimal (since you can always give an appropriate specification),
and it is more likely that any overriding in a body is accidental rather than
intentional. And I can't comment on buggering your book. :-)

The 'later overridding' discussion.

I'm not sure that the current wording (8.3(26.1) and 8.3(26.6)) has this
effect. It's not clear when "an overriding declaration for the full view of the
type" is determined. We want "overriding anywhere" informally, but the ARG has
not liked such wording in the past. Secondly, the first sentence says "shall
not be an overriding declaration for the view of the type at that place." That
rule applies to types without partial views; but really we want that to apply
only for partial views; for other types we want to use the second part of the
rule (the one about full views).

I don't think we have a choice but to use this interpretation for full types.
Otherwise, the visibility gets very messy, and you'd have to allow additional
overridding clauses anywhere.

OTOH, the fact that the check is different (using a partial place rather than
anywhere) for partial views is uncomfortable. (BTW: T is tagged, so NT and NNT
need "with null record"). If we had P.C2:

package P.C2 is
    type NT is new T with private;
    overriding
    procedure Op (Y : NT);     -- Illegal, this doesn't override anything.
    package Nested is
        type NNT is new T with private;
        procedure Op (Y : NNT); -- OK.
    private
        type NNT is new T with null record;
        -- Error: We need "overridding" or "overridding or not" procedure Op here.
	  -- That's because the body of Nested has visibility on primitive 'Op'
    end Nested;
private
    type NT is new T with null record;
    -- P.C.Op overrides P.Op here (P.Op is inherited here).
    -- Thus, we need "overriding procedure Op (Y : NT);" here.
end P.C2;

I'm not expecting Mr. Private to be happy with this, but he'll need a better
idea (and wording for it!) in order to change it. And this is a lot more
important than adding restrictions to "overrides or not".

Generic paragraph question:

Yes. :-)

It is OK.

Second generic question:

Yup. I always preferred allowing the contract to be modified in this way. It
seems to be a useful capability. Moreover, if we allowed that, arguably, we
wouldn't need "overriding or not". (I don't think it makes sense for a generic
to be bisexual: both allowing and not allowing overriding. Generally, you do
not want overriding in a generic, certainly not for mix-in uses.)

?? I concluded that if the partial view said "overriding" then it would be a
burden to require it in the full view as well.

Yes, and useless noise to boot. Why be required to repeat something obvious??

?? One might argue that if the
partial view said "overriding or not" then the full view need not be checked??

Yes, I expect that to be the semantics. Of course, Pascal doesn't want to allow
it in that case, which also would answer the question.

The generic mixin case should that we indeed have to allow "overriding or not"
on a partial view. The good news is that the example is bogus, for two reasons:
"overridding or not" on the partial view should extent to the private part, so
no overridding clause is required (but its allowed). More importantly, where is
PDGT coming from?? There is no such type in the spec. of the generic, and any
outside type wouldn't match the generic formal. You can't construct such an
example with formal private types. We could try:
    type GT is new T with private;
    type PDGT is new T with private;
but I don't know if the derived declaration is legal. If the check is
assume-the-worst, it fails; if it is assume-the-best, it is allowed. The
wording of the language suggests that it is a hole - 7.3(8) is a legality rule
that applies only in the visible part of an instance (that's the default). The
second sentence seems to need to apply to the entire rule, not just "the
requirement that the type is specific".

---- Pascal Leroy

Good job, John, but I think there are a number of nasty issues that
remain to be considered (that's the problem when proposals become more
precise, you can write examples and ask "what if" questions).

My comments interspersed below.

Pascal
--

> In 2.9(3) as modified by AI 284 add the following to the list of
> nonreserved keywords
>
>       overriding
>
> Change the syntax in 6.1 to read
> overriding_indicator ::= overriding [or not]
> subprogram_declaration ::=
>                [overriding_indicator] subprogram_specification ;
> abstract_subprogram_declaration ::=
>    [overriding_indicator] subprogram_specification is abstract;
> overriding_clause ::= overriding_indicator subprogram_specification ;

I like the syntax.  In fact, this is the first time that I see a syntax
that I like for the "optional" case.  Although it has a Norm Cohen
flavor, it reads well, especially considering that it's on a line of its
own.

> Its profile shall be
> fully conformant with the profile of the subprogram_declaration,
> abstract_subprogram_declaration or subprogram_renaming_declaration
> or the profile implied by the generic_instantiation.

Intense hand-waving in the last part of this sentence.  I think you'll
need more words than that.  The problem is that you are requiring full
conformance (which is approximately lexical matching) but the generic
instantiation model in 12.3(13-14) kills you.  Consider:

    generic
        type T is private;
    procedure P (X : T);

    procedure I is new P (Integer);

According to 12.3(13) the profile of the instance is:

    procedure I (X : T)

and 12.3(14) explains that in this context the name T denotes the
subtype Integer.  There is no way that the user can write a subprogram
specification that is fully conformant with this profile.  (It's really
a technicality, in the sense that there is no doubt what the right
answer is here, but writing the words is going to be challenging.)

> In addition to the places where  Legality Rules
> normally apply, these rule also applies in the private part of an
> instance of a generic unit.
>
> ?? What's that last bit for Randy?  Is it still OK???

I don't think it's for Randy.  I believe it only says that all this
overriding checking happens in the private part as well as the visible
part.  It would be silly if we made visible parts "safe" and private
parts "unsafe".  (Or am I missing something?)

This leads me to wonder what happens in a generic body if you derive
from a formal type.  Surely we don't want the legality of the
instantiation to depend on the contents of the body.  It seems that the
AI ought to say a few well-chosen words about this (I suppose we need
some form of assume-the-worst rule).

> package P.C is
>     type NT is new T;
>     overriding
>     procedure Op (Y : NT);     -- OK.
>     package Nested is
>         type NNT is new T;
>         procedure Op (Y : NNT); -- Illegal because the body of Nested has
>                                 -- visibility on primitive 'Op'
>                                 -- We must add "overriding"
>                                 -- or "overriding or not".
>     end Nested;
> private
>     -- P.C.Op overrides P.Op here (P.Op is inherited here).
> end P.C;
>
> package body P.C is
>     package body Nested is
>         -- P.C.Nested.Op overrides P.Op here (P.Op is inherited here).
>     end Nested;
> end P.C;
>
> Note the possibility of using "overriding or not" in this example as
> indicated in the comment; it can be used here to avoid breaking the
> abstraction (privateness) of the original type P.T.
>
> ?? Is Mr Private happy with this??

Mr Privacy is confused.  My understanding is that you never have to add
"overriding or not" to a declaration (except in generics).  In this case
I would expect P.C.Nested.Op to have no overriding_indicator, and the
body to contain an overriding_clause.  That would reflect the fact that
Op doesn't override at the point of its declaration, and it wouldn't
break the privacy of P.T.

Hmm, but we don't allow an overriding_clause in a body, because it must
occur before the freezing point.  Why this rule about freezing?

Note that, contrary to what the comment seems to imply, adding
"overriding" to Op would break the privacy of P.T.

I guess this example needs more thought.

> ??  And so it seems that the earlier remarks that we didn't want to modify
> the contract rules are not right. We can modify the contract to prevent
> overriding but not to require it. Tis an odd business chaps ??

That seems quite broken.  It appears to violate the Great Cosmic Duality
between generics and (normal) private types.  Consider your example:

package P is
   type T is private;
   function "+" (Left, Right: T) return T; -- don't know here
private
   type T is range 0 .. 100;
   overriding
   function "+" (Left, Right: T) return T;  -- now we know
end P;

As the comment correctly points out, the absence of an
overriding_indicator on the partial view really means "heck I don't know
for sure, but so far it doesn't override" and the overriding_clause then
tells the truth when we know it.  Now look at the generic equivalent:

generic
    type T is private;
package G is
    type NT is new T;
    function "+" (Left, Right : T) return T;
end G;

It would seem to me that the natural application of the Great Cosmic
Duality would be to say that the absence of an overriding_indicator on
G."+" really means "don't know" and that the instantiation ought to say
the truth by using overriding_clauses:

type T is range 0..100;

package I is new G(T) with
    overriding
    function "+" (Left, Right : T) return T;
end I; -- John to find a good syntax

And, oh, we wouldn't need "overriding or not" anymore because the
instantiation is the one who would say the truth.

(Sorry for the "stream of consciousness" style here.  I am just
inventing language as I type.  The proposed solution may be totally
bogus, but I think the examples in the AI indicate a deep problem.)

---- Randy Brukardt:

Pascal said:

> This leads me to wonder what happens in a generic body if you derive
> from a formal type.  Surely we don't want the legality of the
> instantiation to depend on the contents of the body.  It seems that the
> AI ought to say a few well-chosen words about this (I suppose we need
> some form of assume-the-worst rule).

I don't believe that we can do assume-the-worst on this rule, since it is an
either-or rule. If we did, we'd reject virtually all generic bodies containing
a derivation (any instantiation MIGHT have an overridding routine) - the only
ones that could work would be those for which all primitive routines have an
overridding indicator (usually "overriding or not").

Since the most important part of the rule is checked in the generic body anyway
(that intentional "overridding" really is), the only check that would not get
made in a generic instance body is the "accidential overridding" one. That
doesn't seem too bad, especially as derivations in bodies are rare.

An AARM note about this probably would be worth having. (Indeed, a lot of the
!discussion probably ought to be in the AARM.)


> > package P.C is
> >     type NT is new T;
> >     overriding
> >     procedure Op (Y : NT);     -- OK.
> >     package Nested is
> >         type NNT is new T;
> >         procedure Op (Y : NNT); -- Illegal because the body of Nested
> >                                 -- has visibility on primitive 'Op'
> >                                 -- We must add "overriding"
> >                                 -- or "overriding or not".
> >     end Nested;
> > private
> >     -- P.C.Op overrides P.Op here (P.Op is inherited here).
> > end P.C;
> >
> > package body P.C is
> >     package body Nested is
> >         -- P.C.Nested.Op overrides P.Op here (P.Op is inherited here).
> >     end Nested;
> > end P.C;
> >
> > Note the possibility of using "overriding or not" in this example as
> > indicated in the comment; it can be used here to avoid breaking the
> > abstraction (privateness) of the original type P.T.
> >
> > ?? Is Mr Private happy with this??
>
> Mr Privacy is confused.  My understanding is that you never have to add
> "overriding or not" to a declaration (except in generics).

You never HAVE to; I think this example shows why you should be allowed to.

> In this case
> I would expect P.C.Nested.Op to have no overriding_indicator, and the
> body to contain an overriding_clause.  That would reflect the fact that
> Op doesn't override at the point of its declaration, and it wouldn't
> break the privacy of P.T.
>
> Hmm, but we don't allow an overriding_clause in a body, because it must
> occur before the freezing point.  Why this rule about freezing?

So that there is a clear point at which the checking can be done. We need to
know when the compiler has to go back and check all of the partial view
subprograms that don't have overridding_clauses or an overriding_indicator. If
you allowed overriding_clauses to happen in the body, you'd have to defer that
check until you completed the compilation of the body. Which can be days or
months later. I don't think we want an error in the spec. of a routine to
fester until someone happens to compile a body. And then you'd have to somehow
figure out when there was no body in order to do the check at the end of the
spec.

> Note that, contrary to what the comment seems to imply, adding
> "overriding" to Op would break the privacy of P.T.
>
> I guess this example needs more thought.

Yes; the compiler always knows that the routine is overriding, but supposedly
the programmer does not. I think that this example really shows why you have to
have "overridding or not" everywhere, because it is the only way to avoid
breaking privacy in some cases.

Note, however, that this is a dubious design. Usually, if you are intentionally
overridding the routine, you would want to continue to do so in the private
part (the routine ought to stay private). And most types ought to be private
anyway; note that my similar example (which uses private types) has no problems
with breaking privateness for NT.

If you accidentially are overridding the private routine, that is exactly the
case where trouble can happen and exactly what we're trying to detect. You
really do need to break privateness enough to realize that "Op" is a bad name
for this operation if you aren't intending to override the private. So I have
to think that breaking privateness is inherent in the check. (Which is too
bad.)

> > ??  And so it seems that the earlier remarks that we didn't want to modify
> > the contract rules are not right. We can modify the contract to prevent
> > overriding but not to require it. Tis an odd business chaps ??
>
> That seems quite broken.  It appears to violate the Great Cosmic Duality
> between generics and (normal) private types.  Consider your example:

That duality really doesn't exist in Ada 95 as it is (the sharing enabling
rules among others see to that), and if we adopt "limited with", it will be
completely dead (since "limited with" doesn't work at all with instantiations,
meaning that it is useless if some of the types are declared in generics). So I
think trying to preserve it here is questionable at best.

Your two examples don't even look similar; I have a hard time believing anyone
will be confused.

> It would seem to me that the natural application of the Great Cosmic
> Duality would be to say that the absence of an overriding_indicator on
> G."+" really means "don't know" and that the instantiation ought to say
> the truth by using overriding_clauses:
>
> type T is range 0..100;
>
> package I is new G(T) with
>     overriding
>     function "+" (Left, Right : T) return T;
> end I; -- John to find a good syntax
>
> And, oh, we wouldn't need "overriding or not" anymore because the
> instantiation is the one who would say the truth.

If you want to kill this idea, this is a wonderful way to do it. The last time
I was working on 218, I pretty much concluded it was intractable and that the
idea had to be abandoned.

John managed to rescue it with "overridding_clause"s, and we now seem to be
near a solution. But if we start adding this to instantiations, the complexity
factor has gone far beyond the benefits.

I'm wondering personally if the idea of catching "accidential overriding" is
worth the effort. If we stopped trying to do that (and left "no indicator" as
"don't care"), it seems like most of these privateness problems (and the
weirdness of the partial view rules) would go away.

Come to think of it, why are we using a configuration pragma anymore? Once we
have syntax, we can made the default to be "don't care" (that is, Ada 95
rules). Perhaps if we explicitly indicate the other cases:

     not overriding
     procedure Foobar (Pascal, John : ...);

It's mildly annoying to have to write more to be safe, but then again that's
what Ada's about. Then we don't have to try to describe where checking is done
(it better be true at the point of the declaration of the overriding
indicator); we don't have to describe where the pragma applies; and we probably
could even allow overriding_clauses after freezing (because there is no
rechecking - all checks occur at the point of the declaration/overriding_clause
in question).

One could imagine a tool or mode that tried to insure that all subprograms
ultimately had an overriding_indicator or overriding_clause, but we could leave
that for the style people and avoid having to worry about breaking privateness
ourselves (if someone wants to break privateness to enforce a style, that's not
our problem).

Perhaps that should be an alternative #3??? (We need alternative #2 to prove
why having the default be safe gets us into trouble.

---- Pascal Leroy

> Since the most important part of the rule is checked in the
> generic body anyway (that intentional "overridding" really
> is), the only check that would not get made in a generic
> instance body is the "accidential overridding" one. That
> doesn't seem too bad, especially as derivations in bodies are rare.
>
> An AARM note about this probably would be worth having.
> (Indeed, a lot of the !discussion probably ought to be in the AARM.)

I'm not sure if we are discussing the same thing.  The thing that bothers me
is that, in John's current write-up, the overriding_indicator (or more
precisely, the absence thereof) changes the contract.  Consider the
following (note that this is the untagged case, as I believe that in the
tagged case 3.9.1(4) saves us):

    generic
        type GT is new T;
    package Gen is
        ...
    end Gen;

    package body Gen is
        type DGT is new GT;
        procedure Op (Z : DGT);
    end Gen;

As I read the AI, it would seem that an instantiation of Gen is illegal if
the actual type has an Op.  At this point Mr. Shared Generic should have a
heart attack.

One way out of this conundrum is to say that in generic bodies, primitive
operations of types that are derived from a formal type fall in the "don't
know" category.  Whether this has to be stated explicitly by writing
"overriding or not" or whether this is the default (and "overriding" is
illegal) is another issue.  (Note that this would argue in favor of having
"don't know" be the default, something you propose later on.)

> > Mr Privacy is confused.  My understanding is that you never have to
> > add "overriding or not" to a declaration (except in generics).

Well, the comment "We must add 'overriding' or 'overriding or not'" seems to
imply the contrary.  I believe that this comment is wrong anyway.

> > Hmm, but we don't allow an overriding_clause in a body, because it
> > must occur before the freezing point.  Why this rule about freezing?
>
> So that there is a clear point at which the checking can be
> done. We need to know when the compiler has to go back and
> check all of the partial view subprograms that don't have
> overridding_clauses or an overriding_indicator. If you
> allowed overriding_clauses to happen in the body, you'd have
> to defer that check until you completed the compilation of
> the body. Which can be days or months later.

Note that we have at least one case where this happens today, viz. the case
of an incomplete type completed in the body, where you use 'Class in the
spec.  OK, this is particularly elegant language design, but at least that's
a precedent ;-)

My model is that the user writes on the declaration an overriding_indicator
which reflects the situation at this place.  If the situation later changes,
he has to add an overriding_clause.  If that's months later, fine, but at
least it will be a conscious decision to override or not.  The places where
implicit declarations occur (and therefore where overriding occur) are very
precisely defined by the RM, and these are the places where
overriding_indicators/_clauses should occur.

Let me come back to my generic example again:

    generic
        type T is private;
    package G is
        type NT is new T;
        function "+" (Left, Right : T) return T;
    end G;

In the generic, "+" doesn't override anything.  I am inclined to think that
there is no point in saying "overriding or not", since there is no "+" in
sight, and the situation is perfectly clear.  Compare this with the case
where T is a formal integer type, and where evidently "overriding" would be
required.

In the case of the formal private type, "+" may become overriding on the
instantiation:

    type T is range 0..100;
    package I is new G(T);

Here we have two options:

1 - Provide some syntax to specify that I."+" is overriding.  This is the
"safe" solution, as it makes possible to control overriding even in
generics, but at the cost of possibly heavyweight syntax.

2 - Ignore the issue and say that it's OK for a declaration that was not
overriding in the generic to become overriding in the instance.  From the
perspective of the instance, it is exactly as if you had "overriding or
not".  But from the perspective of the generic this is a bit safer as you
have a way to express that "+" is not overriding (so if the formal part is
later changed and T gets a primitive "+", you will be informed that there is
potentially a problem).

Am I saying that we don't need "overriding or not" after all?

> If you want to kill this idea, this is a wonderful way to do
> it. The last time I was working on 218, I pretty much
> concluded it was intractable and that the idea had to be abandoned.
>
> John managed to rescue it with "overridding_clause"s, and we
> now seem to be near a solution. But if we start adding this
> to instantiations, the complexity factor has gone far beyond
> the benefits.

I don't think "kill" is a very productive word here.  I was trying to look
at the implications of the model, which is currently not satisfactory for
generics.

I am actually much more optimistic about this AI than I ever was.  First, we
have good syntax for the first time.  Syntax is not nearly as important as
semantics of course, but it's the first thing that people see, so it can be
a stumbling block.  Second, we have (with the overriding_clause) a good
solution to deal with overriding occurring at diverse places in the program
text.  There are still issues to be resolved, notably for generics, but we
are certainly starting to have a much deeper understanding of these issues.

(Remember, this is an AI that was approved by WG9 two years ago, and we were
entirely clueless about the problem then.)

> Come to think of it, why are we using a configuration pragma
> anymore? Once we have syntax, we can made the default to be
> "don't care" (that is, Ada 95 rules). Perhaps if we
> explicitly indicate the other cases:
>
>      not overriding
>      procedure Foobar (Pascal, John : ...);

I don't think changing the default simplifies the definitional problems with
generics, private types, overriding occurring in odd places, etc.  It just
means that you have to write different combinations of keywords to achieve
the same effect.

This being said, this is an attractive idea.  The pragma Explicit_Overriding
always gave me bellyaches, so I'd be happy to get rid of it.

For people who want to be safe and are not excited about writing their own
ASIS tool, we could actually provide restrictions to control what checks
ought to be performed:

    pragma Restrictions (No_Implicit_Overriding);
    pragma Restrictions (No_Implicit_Overloading);

No_Implicit_Overriding would require that you write "overriding" when you
override a subprogram.  No_Implicit_Overloading would required that you
write "not overriding" when you declare a new overload.  Using the two
restrictions together would require that you write either "overriding" or
"not overriding" before each declaration.  (And maybe "overriding or not" if
we have to keep this one for generics.)

> It's mildly annoying to have to write more to be safe, but
> then again that's what Ada's about.

That doesn't bother me as it would be easy to write a tool to add the
overriding_indicators as appropriate (I could write such a tool in a couple
of days).  One could argue that all these overriding_indicators would
degrade readability, but with the restrictions you could choose the
trade-off between readability and safety.

---- Randy Brukardt:

> > Since the most important part of the rule is checked in the
> > generic body anyway (that intentional "overridding" really
> > is), the only check that would not get made in a generic
> > instance body is the "accidential overridding" one. That
> > doesn't seem too bad, especially as derivations in bodies are rare.
> >
> > An AARM note about this probably would be worth having.
> > (Indeed, a lot of the !discussion probably ought to be in the AARM.)
>
> I'm not sure if we are discussing the same thing.  The thing
> that bothers me
> is that, in John's current write-up, the overriding_indicator (or more
> precisely, the absence thereof) changes the contract.  Consider the
> following (note that this is the untagged case, as I believe
> that in the
> tagged case 3.9.1(4) saves us):
>
>     generic
>         type GT is new T;
>     package Gen is
>         ...
>     end Gen;
>
>     package body Gen is
>         type DGT is new GT;
>         procedure Op (Z : DGT);
>     end Gen;
>
> As I read the AI, it would seem that an instantiation of Gen
> is illegal if
> the actual type has an Op.  At this point Mr. Shared Generic
> should have a
> heart attack.

No, you're forgetting 12.3(11): legality rules aren't checked in an instance
body. So there is no check, and the instantiation is legal. That IS what I was
talking about. It's annoying to not have that check, but it follows
automatically from the existing Ada rules. We probably ought to have a note,
though, and your confusion shows why.

> > > Hmm, but we don't allow an overriding_clause in a body, because it
> > > must occur before the freezing point.  Why this rule about freezing?
> >
> > So that there is a clear point at which the checking can be
> > done. We need to know when the compiler has to go back and
> > check all of the partial view subprograms that don't have
> > overridding_clauses or an overriding_indicator. If you
> > allowed overriding_clauses to happen in the body, you'd have
> > to defer that check until you completed the compilation of
> > the body. Which can be days or months later.
>
> Note that we have at least one case where this happens today, viz. the case
> of an incomplete type completed in the body, where you use 'Class in the
> spec.  OK, this is particularly elegant language design, but at least that's
> a precedent ;-)

One that we're planning to make Obsolecent, simply because its such a bad
design. Please, let's not make that mistake again...

> My model is that the user writes on the declaration an overriding_indicator
> which reflects the situation at this place.  If the situation later changes,
> he has to add an overriding_clause.  If that's months later, fine, but at
> least it will be a conscious decision to override or not.  The places where
> implicit declarations occur (and therefore where overriding occur) are very
> precisely defined by the RM, and these are the places where
> overriding_indicators/_clauses should occur.

That's a fine model, but it will cause significant extra implementation effort.
That's because the visibility of these things is a separate set of magic from
determining whether they override or not (which uses visibility only to
determine if it will never override - in large part because there is no visible
semantic difference between overriding early or late - only between not
overriding at all and overriding). That means any check such as you envision
has to take into account a lot of visibility information which is unrelated to
the overrides or not decision.

And I'm convinced if you want to use that model, you have to use an explicit
"not overriding" tag.

> Let me come back to my generic example again:
>
>     generic
>         type T is private;
>     package G is
>         type NT is new T;
>         function "+" (Left, Right : T) return T;
>     end G;
>
> In the generic, "+" doesn't override anything.  I am inclined to think that
> there is no point in saying "overriding or not", since there is no "+" in
> sight, and the situation is perfectly clear.  Compare this with the case
> where T is a formal integer type, and where evidently "overriding" would be
> required.
>
> In the case of the formal private type, "+" may become overriding on the
> instantiation:
>
>     type T is range 0..100;
>     package I is new G(T);
>
> Here we have two options:
>
> 1 - Provide some syntax to specify that I."+" is overriding.  This is the
> "safe" solution, as it makes possible to control overriding even in
> generics, but at the cost of possibly heavyweight syntax.
>
> 2 - Ignore the issue and say that it's OK for a declaration that was not
> overriding in the generic to become overriding in the instance.  From the
> perspective of the instance, it is exactly as if you had "overriding or
> not".  But from the perspective of the generic this is a bit safer as you
> have a way to express that "+" is not overriding (so if the formal part is
> later changed and T gets a primitive "+", you will be informed that there is
> potentially a problem).
>
> Am I saying that we don't need "overriding or not" after all?

Yes. 2 is essentially saying that the rules are not enforced in an instance at
all. I don't view that as very safe.

But I do not like either of these solutions. I'm in favor of solution 3 (at
least for generic specs):
3 - Overriding indicators are part of the "contract". Thus, this instantiation
is illegal - the rechecking of the instance spec fails.

Note that my original proposal did NOT check these indicators (they were
pragmas then) in the generic specification. The idea was that they WERE a first
class part of the contract. Argubly, they should be up top with the formal
types, but that seems way too heavy.

> > If you want to kill this idea, this is a wonderful way to do
> > it. The last time I was working on 218, I pretty much
> > concluded it was intractable and that the idea had to be abandoned.
> >
> > John managed to rescue it with "overridding_clause"s, and we
> > now seem to be near a solution. But if we start adding this
> > to instantiations, the complexity factor has gone far beyond
> > the benefits.
>
> I don't think "kill" is a very productive word here.  I was trying to look
> at the implications of the model, which is currently not satisfactory for
> generics.

I think it's fine, and your alternatives are worse (and I expect that my
alternative will get little support as well).

> I am actually much more optimistic about this AI than I ever was.  First, we
> have good syntax for the first time.  Syntax is not nearly as important as
> semantics of course, but it's the first thing that people see, so it can be
> a stumbling block.  Second, we have (with the overriding_clause) a good
> solution to deal with overriding occurring at diverse places in the program
> text.  There are still issues to be resolved, notably for generics, but we
> are certainly starting to have a much deeper understanding of these issues.
>
> (Remember, this is an AI that was approved by WG9 two years ago, and we were
> entirely clueless about the problem then.)

Agreed with that. One reason I never implemented it was that I couldn't figure
out how to decide when a subprogram was "not overridden", because there was no
"point" at which to check. I should have realized that that meant that there
was a significant problem in the model.

> > Come to think of it, why are we using a configuration pragma
> > anymore? Once we have syntax, we can made the default to be
> > "don't care" (that is, Ada 95 rules). Perhaps if we
> > explicitly indicate the other cases:
> >
> >      not overriding
> >      procedure Foobar (Pascal, John : ...);
>
> I don't think changing the default simplifies the definitional problems with
> generics, private types, overriding occurring in odd places, etc.  It just
> means that you have to write different combinations of eywords to achieve
> the same effect.

Actually, it does, because it means that we can say that the check always
occurs at the point of the overriding indicator. We can't do that now, because
the absence of an indicator means that a check is done "sometime" that there is
no overriding. All of your concerns with the placement of overriding_clauses
stem from that, and all of that can be eliminated - along with the freezing
requirement. (Although I guess with the existing model that you would prefer
that the freezing requirement be eliminated and that all of the checks be
repeated anytime that the visibility changes, which I think is silly.)

Also, the "implicit" generic contract isn't quite so bad, because it is always
spelled out with an overriding indicator. Admittedly, its still buried, but
that is true of anything that causes an error in the
assume-the-best-and-recheck-the-instance model -- such as deriving from a
library-level tagged type and having to instantiate at library level. That's an
"implied contract", and it is a far less explicit contract than this one would
be.

> This being said, this is an attractive idea.  The pragma Explicit_Overriding
> always gave me bellyaches, so I'd be happy to get rid of it.
>
> For people who want to be safe and are not excited about writing their own
> ASIS tool, we could actually provide restrictions to control what checks
> ought to be performed:
>
>     pragma Restrictions (No_Implicit_Overriding);
>     pragma Restrictions (No_Implicit_Overloading);
>
> No_Implicit_Overriding would require that you write "overriding" when you
> override a subprogram.  No_Implicit_Overloading would required that you
> write "not overriding" when you declare a new overload.  Using the two
> restrictions together would require that you write either "overriding" or
> "not overriding" before each declaration.  (And maybe "overriding or not" if
> we have to keep this one for generics.)

Not quite: a totally new identifier wouldn't be protected.

Besides, don't you think that defining these properly would be as hard as
defining Explicit_Overriding? The issues of where to check certainly occur here
as well; it's precisely them that I want to get rid of. And certainly the
generic issues would exist.

We could informally suggest such things in the AARM, but I'm pretty sure we
wouldn't want to try to define them.

> > It's mildly annoying to have to write more to be safe, but
> > then again that's what Ada's about.
>
> That doesn't bother me as it would be easy to write a tool to add the
> overriding_indicators as appropriate (I could write such a tool in a couple
> of days).  One could argue that all these overriding_indicators would
> degrade readability, but with the restrictions you could choose the
> trade-off between readability and safety.

Yes, its the readability issue that I think would be significant. Especially to
anyone that hasn't struggled with the generic model.

----End 3rd thread.
----End private discussion.

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

From: John Barnes
Sent: Wednesday, May 14, 2003  1:34 AM

Attached is a rewrite of AI-218 on overriding.

It captures a number of issues that I discussed with Randy
and Pascal before revealing my inadequate understanding of
Ada to the general public.

I expect we will discuss it at length in Toulouse.

[Editor's note: This is version /04 of the AI.]

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

From: Tucker Taft
Sent: Wednesday, May 14, 2003  8:15 AM

I don't remember talking about "overriding or not"
as the syntax.  It is a bit bizarre, but I'm sure
Norm Cohen would love it, and I'm willing to play along.

I note one "bug" in the discussion.  Formal derived
private types do have one operation, namely "=",
and presumably overriding should be used with
that one.

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

From: Pascal Leroy
Sent: Wednesday, May 14, 2003  9:02 AM

The minutes of the Padua meeting have:

"We decide to put the keyword in front. John is asked to find a clever
idea for the optional case."

John tapped his indefatigable imagination and came up with this syntax
for the optional case.  I must say that I like it better than anything
that has been proposed so far.

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

From: Robert Dewar
Sent: Wednesday, May 14, 2003  9:08 AM

Those were jokes from Norm!

I dislike this kind of keyword joke, except as a joke. I can't believe
that someone would seriously suggest such ugly abuse of OR or NOT

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

From: Tucker Taft
Sent: Wednesday, May 14, 2003  10:50 AM

I don't feel as strongly as Robert on this one,
but here are some alternatives:

   allow overriding
   procedure blah(...);

   possible overriding
   procedure blah(...);

   potential overriding
   procedure blah(...);

Of the three, I probably prefer "possible".
"Allow" sounds like we are allowing overriding of this routine
in subsequent descendants, rather than allowing this subprogram
to be an overriding.

I believe our latest thinking permits these only
in the visible part of a generic package.  One possibility
is to simply relax the rules and say that no overriding check is
performed on an instance, making "possible overriding" the
default in a generic, in other words.

A third possibility is to make "possible overriding" the default
in a generic, but allow an explicit "not overriding" prefix
if desired, which is the default everywhere else.  In a generic,
if given explicitly, "not overriding" means "not overriding even
in the instance."

E.g.:

    type NT is new formal_type [with ...];

    not overriding
    procedure Blah(X : NT);

means that Blah must not be overriding an operation that is
inherited from formal_type, including in the instance.

I suppose this third possibility is my mild favorite.  It allows
users to be explicit everywhere if they like, and only in a generic
is there a third option, which is between overriding and not overriding,
requiring the "not overriding" to be explicit.

One reason I prefer this is that it seems to me an unusual
generic that really *cares* whether it is overriding in
the instance.  I would rather not have to go and add
"possible overriding" in all my generics, whereas I am
quite happy to add "overriding" as necessary to be able
to get additional checking.

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

From: Robert Dewar
Sent: Wednesday, May 14, 2003  11:15 AM

I must say that so far I preferred the pragma solution, I have no
objection to a non-pragma solution if a decent syntax can be found,
but so far I have not seen evidence of this.

I also think a pragma solution is better because it allows
earlier implementation, and also btter forwards/bacwards comatpiblity.

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

From: Tucker Taft
Sent: Wednesday, May 14, 2003  11:52 AM

I originally favored a pragma solution, but was convinced
by how prevalent these annotations would be.
Almost every dispatching operation that is not
in the "root" type will need this annotation.
That seems to make them inappropriate for a pragma,
in my eyes, or at least a pragma having "good taste." ;-)

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

From: Randy Brukardt
Sent: Wednesday, May 14, 2003  3:17 PM

The real problem is that it isn't possible to solve the problem with pragmas
alone, at least with the existing syntax of pragmas.

John, Pascal, and I had a lengthy private discussion on this AI which we've
since decided needed to be made public (since it covered a lot of annoying
issues). One possibility which I will explore further is eliminating the
pragmas and "optional overridding" altogether, by making the default be
"don't care". This is slightly less safe, but it appears to be less
complicated.

In any case, this is a lot harder to do than it appears at first glance. Any
solution works well in the 'typical' cases, but getting it right for
generics and for private types with additional operations is hard.

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

From: Robert Dewar
Sent: Wednesday, May 14, 2003  4:28 PM

That seems amazing, because the only syntactic requirement for pragmas is
that the arguments have the syntax of expressions (they can have any old
seman6tics you want).

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

From: David Emery
Sent: Wednesday, May 14, 2003  4:35 PM

Yeah, but I remember that the general intent of pragma-hood is to
limit the effects of a pragma on legality or language-specific semantics.
Doing this kind of thing with a pragma strikes me as A Bad Thing.

Also, it strikes me that "override" and its verb forms are likely to
appear as identifiers in existing real program:
	if authorized or override then
	   launch_the_missile;
	else
	  beep_annoyingly_at_operator;
	end if;

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

From: Robert Dewar
Sent: Wednesday, May 14, 2003  6:32 PM

Lots of pragmas affect legality, here is a partial list

elaborate
elaborate_body
elaborate_all
inline
import
convention
restrictions (!)
pack
preealborate
pure

well that's off the top of my head

Many others affect language-specific semantics

remote_types
suppress
atomic
volatile
c_pass_by_copy
locking_policy
discard_names

again that's off the top of my head

Actually it takes more work to think up a list of pragmas that do NOT
affect either legality or run-time semantics.

So there may be good arguments against the use of a pragma, but this is
not one of them!

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

From: Gary Dismukes
Sent: Wednesday, May 14, 2003  4:18 PM

Tuck wrote:
> I suppose this third possibility is my mild favorite.  It allows
> users to be explicit everywhere if they like, and only in a generic
> is there a third option, which is between overriding and not overriding,
> requiring the "not overriding" to be explicit.

The idea of making "possible overriding" the default for the
generic case is attractive.  (Presumably this would only apply
to primitives of types derived from formal types.)

> One reason I prefer this is that it seems to me an unusual
> generic that really *cares* whether it is overriding in
> the instance.  I would rather not have to go and add
> "possible overriding" in all my generics, whereas I am
> quite happy to add "overriding" as necessary to be able
> to get additional checking.

I agree, it seems like it would be really annoying to have to
apply the "possible" indication to all primitives in a generic.

The drawback is that it's a little uncomfortable to have different
defaults for the generic vs. normal case and the inconsistency
has the potential to cause confusion.  However it does seem
to make the feature easier to use.

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

From: Tucker Taft
Sent: Wednesday, May 14, 2003   9:21 PM

> The idea of making "possible overriding" the default for the
> generic case is attractive.  (Presumably this would only apply
> to primitives of types derived from formal types.)

I think it need only apply for the check in an instance.
There need not be any change in the semantics when compiling
the generic itself.  Essentially, the default would be
"this doesn't override any primitive in the generic,
and I don't care whether it overrides any primitive in the instance."
Explicitly saying "not overriding" would mean "this doesn't
override any primitive in the generic, and it *also* doesn't
override any primitive in the instance."

The distinction between generic and instance only exists for a type
derived directly or indirectly from a generic formal type,
so the distinction between "" and "not overriding" only exists
in a generic.  In all other contexts, they mean the same thing.


> I agree, it seems like it would be really annoying to have to
> apply the "possible" indication to all primitives in a generic.
>
> The drawback is that it's a little uncomfortable to have different
> defaults for the generic vs. normal case and the inconsistency
> has the potential to cause confusion.  However it does seem
> to make the feature easier to use.

If you take the approach I suggest above, the default
is effectively equivalent to "not overriding" everywhere except
in a generic, because only in a generic is there the distinction
between the check on the generic and the check on the instance.

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

From: Gary Dismukes
Sent: Thursday, May 15, 2003  12:47 AM

Makes sense, thanks for the clarification.  I'm in favor of this approach.

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

From: Robert I. Eachus
Sent: Wednesday, May 14, 2003  9:05 PM

First let me say that my strong preference is that the default is may
override.  If the keyword solution is preferred, for example,
"overriding" means that this declaration must override, "not overriding"
means that the subprogram must not override, and no keyword is status
quo ante.  So this eliminates the need for the environment pragma, and
answers all the potential questions about mixing new and old code.

Robert Dewar wrote:

> So there may be good arguments against the use of a pragma, but this is
> not one of them!

In fact I think that if we go with the default as may or may not
override, there is a huge benefit to a solution using pragmas.  If the
pragmas are present but the compiler used doesn't recognize the new
pragmas?  No problem.  But the original proposal and variations requires
  an upwardly incompatible change.  If the justification was strong, I
might vote for a change that induced compatibility problems.  Making the
default may or may not and using pragmas is totally upwardly compatible.
  People who like the idea can start coding that way tomorrow.

So I think that one of the major benefits of the pragma approach is this
ability to start using the feature before compiler support is ready, and
not have problems if, for example, your target compiler doesn't support
the pragmas, but the compiler used for initial testing on the host does.
  You get the benefit of the pragmas during development, and no worries
that the source has to be modified for the target compiler.

One last point.  There is a potential problem with the pragma approach
when several declarations in the same declarative part have the same
name.  I think that the pragmas should apply to all declarations with
the same name, as most of the time that is exactly what will be desired.
(For example, if you have  several Finalize operations declared in the
same scope, it will be highly unusual to want only some of them to
override.)

But there needs to be a way to deal with the unusual case.  I think that
I prefer that the pragma normally apply to all declarations in scope.
But if there are two or more pragmas applying to the same name, the
first should apply to declarations before its point of occurance, and
the second declaration, should apply up to the point of its occurance
and so on.  That way the pragma can be put directly after the
declaration(s) it applies to.

But in any case, you must have all three pragmas available (or a pragma
with three arguments), independent of the default.  I prefer pragmas
Overrides, No_Overriding, and May_Override.

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

From: Tucker Taft
Sent: Wednesday, May 14, 2003   9:26 PM

Robert I. Eachus wrote:
> First let me say that my strong preference is that the default is may
> override.  If the keyword solution is preferred, for example,
> "overriding" means that this declaration must override, "not overriding"
> means that the subprogram must not override, and no keyword is status
> quo ante.  So this eliminates the need for the environment pragma, and
> answers all the potential questions about mixing new and old code.

That is the default in the absence of the pragma.  The
whole point of the configuration pragma is to make
the default "not overriding."  So if you prefer the
default being "may override" then you won't use the
configuration pragma.  But many people want the confidence
that overriding happens only when explicitly requested.
For them, the configuration pragma provides that.
In fact, even if we didn't standardize it, I suspect the
configuration pragma would be invented!  It is clearly
a useful guarantee to provide in some environments.

As far as going back to pragmas, please believe that that
ground has been well tilled, several times.  Pragmas really
don't work very well for various and sundry technical reasons, and having
to use them pervasively I believe is a serious misuse of pragmas.

You should definitely read the minutes from the past few meetings
on this AI to fully understand the issues.

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

From: Robert I. Eachus
Sent: Thursday, May 15, 2003  1:22 AM

Tucker Taft wrote:

> You should definitely read the minutes from the past few meetings
> on this AI to fully understand the issues.

Oh, I understand the issue all right.  Let me sneak in one other
advantage to pragmas, and then I will discuss why I think a pragma or
pragmas is the right approach.

If we use the pragma approach, then it is possible to have two
variations which will make the pragmas much more useful.  The first is
that if the pragma does not contain a subprogram name, or a list of
subprogram names if that is allowed, then the pragma should apply to all
subprograms declared in the scope.  This is often what you want if you
are creating a descendent of a tagged type in a package.  All of the
subprograms declared in the scope are expected to be overloading.  But
there are also cases where most of the subprograms are explicit
overloads, but there are one or two operations added for this (OO not
Ada) subtype.  So if the pragmas are allowed with no arguments, then a
pragma with a specific argument will only apply to that name.

Doing this would make using the feature much less obtrusive.  It is
possible to go further, and allow type names as parameters to the
pragmas.  This would mean that all operations of that type declared in
this scope are expected to be overloading.  (Or non-overloading
depending on the pragma used, but for type names the first will be much
more common.)

Okay, now to raise the flaming sword and cry havoc! on the pragma vs
(non-)reserved word issue.  The purpose of these annotations (and
whatever form they take, that is all they are) is to promote program
correctness.  A good and just cause.  But if the feature is not used, it
won't help.  And even more important, if there are a mixture of usage
styles in the wild, then distributing Ada components becomes much more
difficult, you need one version that uses the feature and one that does not.

Now let's look at the world where instead of on a per library basis, the
feature is used on a per unit basis.  Compilers can have all sorts of
compilation unit pragmas, or more realistically compile time switches
that control error and warning messages.  On an individual preference
basis we will probably see ignoring missing pragmas, and warnings for
missing pragmas as the two favorites.  Software development plans and
style guides will probably require the pragmas to be present, even if
you want the default (whatever that turns out to be).  But in all
compiler modes, if one of the pragmas is present but violated, that
should be reported as an error.

If this is the way the world ends up, then those who are willing to pay
the minor overhead of using the pragmas will be happy.  Development
environments will have templates that supply the pragmas, and there will
be tools to add the pragmas where they are missing.  (Useful perhaps,
for lazy programmers, but more useful for converting existing software
to use the feature.)

But all of these features will blunt the usefulness of the feature.
(Notice that this can happen just as well with the non-pragma version.)
  What you really want is for the programmer to think, and tell the
compiler what he thinks.  That is why I think that allowing the type
name as a pragma argument is such a win.  When programmers declare a new
derived tagged type, they will document their expectation--all
overloading, no overloading, or some mix.

It might be possible to change the language syntax to have a specific
portion of the declarative part where overloading subprograms, and only
overloading subprograms can appear.  But I think that begins to look
more like C++ than Ada.

Pragmas that apply to all the operations of derived tagged types in the
scope I think will make the cost of the feature small to the programmer,
and the likelihood that the programmer will think while he is using it
fairly high.

Oh, one last point.  Whether the pragma or non-reserved word sides win,
the effect of applying the pragmas or non-reserved words to subprograms
that are not operations of a derived tagged type should be an error
outside of generics.  (I can see cases where you want to use them in
generics package specifications even when it is not clear to the
compiler that the applicable generic formal type will be tagged.  For
generic formal packages, the compiler will know.)

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

From: Tucker Taft
Sent: Thursday, May 15, 2003   8:25 AM

The configuration pragma can be used library-wide, or
on an individual source file (aka "compilation").
I think this gives the flexibility needed, while
also allowing the project-wide control if desired.

Robert I. Eachus wrote:
> Tucker Taft wrote:
>
>> You should definitely read the minutes from the past few meetings
>> on this AI to fully understand the issues.
>
> Oh, I understand the issue all right...

If so, then you should address the specific issues in the minutes
before launching off on other topics!

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

From: Robert I. Eachus
Sent: Thursday, May 15, 2003  11:44 AM

If I there is something missing in the draft minutes of the Padua
meeting, you should probably suggest adding it. Other than that, I think
the arguments are summed up in version 2 of the draft AI as:

"An advantage over pragmas is that the syntax is clearly part of the
declaration whereas pragmas are not. In the alternative approach the
pragmas had to immediately follow the declaration (with optional
inclusion of the subprogram identifier) and required special rules for
the pragmas to ensure that they only applied to the immediately
preceding declaration. The normal rules would have been that the pragma
applied to all overloaded declarations with the same identifier which
would clearly be inappropriate. There are also dangers if the pragmas
get separated from the declaration during program amendment if the
identifier is not included and including it seems a burden."

I thought those were the issues I was addressing. The first statement is
obvious and an argument for the syntax change which I accept.  However,
I think that the advantages of the all pragma approach outweigh the
disadvantages.  I don't really buy the argument about special rules for
pragmas being needed.  There will be cases where overriding and
non-overriding subprograms with the same name make sense, for example, a
Create operation.  My proposal does address that case.  The dangers
mentioned in the last sentence I definitely disagree with.  With the
pragma solution my choice would be to place the pragmas directly after
the derived type declaration:

type Foo is new Ada.Finalization.Controlled with private;
pragma Overrides(Initialize, Finalize);

As long as there is a rule/understanding by compiler vendors that it is
an error when there is no corresponding declaration, this placement is
much more useful to the maintainer.  As for the author, locating the
pragma directly after the type declaration would be much more likely to
mean that he thought about the overriding issue.

Some bookkeeping if you will.  Placing the prama(s) directly after the
type declaration (or after the full declaration in the private part)
argues strongly for the configuration pragma Explicit_Overriding with
the currently documented meaning.  That way you get some benefit from
using the pragma Overrides even absent the Explicit_Overriding pragma,
and the full benefit when the Explicit_Overriding changes the default
from may override to does not override.  You still need the
non-overriding and may override pragmas in both cases, and a compiler
option to warn about potentially overriding subprograms which are not
covered by a pragma.

This causes a slight problem with the Explicit_Overriding pragma because
you really need two versions.  My choice of how to do that would be to
have two pragma arguments Strict and Mild, with Mild the default.  Mild
would mean that the compiler would only flag as errors cases where an
overriding declaration was not flagged as such, the strict version would
require that all such declarations be explicitly flagged as overriding,
non-overriding or don't care.  Back to my example above, I would expect
the normal style under the strict version to be:

type Foo is new Ada.Finalization.Controlled with private;
pragma Overrides(Initialize, Finalize);
pragma Non_Overriding(Foo);

This would mean that Initialize and Finalize are overriden, and that
there are other operations for Foo declared here that are non-overriding.

Again I strongly feel that the best place for this information is right
after the derived type declaration, or the full type declaration for
private types where the full declaration is a derived type.  There will
be cases where this preferred location can't be used or doesn't make
sense, but I feel that is a decision for the programmer, not the ARG.

Imagine a ten page package declaration where there is an overriding of
Finalize on page 6.  That is at least as hard to find as the Finalise
declaration used as an argument for this feature.  If the pragmas are
located just after the type declaration, that is going to make things
much easier for the maintainer, or for someone writing a package that
further derives from the type in the hypothetical ten-page package
declaration. (Text_IO is only five.)

Which brings up one last point.  Are there any standard library packages
that are going to need to change as a result of this AI?  I can't think
of any current packages, but there are some proposed new container
packages that will.

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

From: Robert Dewar
Sent: Thursday, May 15, 2003  1:43 PM

> People who like the idea can start coding that way tomorrow.

Also implementors who like the idea can implement it tomorrow :-)

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

From: Pascal Leroy
Sent: Thursday, May 15, 2003  4:37 PM

I am sick and tired of rehashing the same arguments over and over again,
so let me quickly say this:

We tried with pragmas.  As a matter of fact, we wrote the AI with
pragmas initially, for all the good reasons that were listed (again) in
this thread.  As a matter of fact, this AI went all the way up to WG9
and was approved.  It only had one minor problem: it was all wrong.

In order to deal with complicated situations involving private types,
you need to be able to designate one particular subprogram among a set
of overloaded subprograms.  If you don't want to force users to add
renamings all over the place, this means that you need a way to specify
a subprogram parameter profile in a pragma, e.g.:

	pragma Foo (function F (X : Float) return Boolean);

That's new syntax, so if we have to have new syntax we might as well do
it right.

See the end of the appendix of
http://www.ada-auth.org/cgi-bin/cvsweb.cgi/AIs/AI-00218.TXT?rev=1.14 for
details.

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

From: Randy Brukardt
Sent: Thursday, May 15, 2003  7:43 PM

Pascal said:
> I am sick and tired of rehashing the same arguments over and
> over again, so let me quickly say this:

I had written essentially this same message when the power went off here,
dumping it into the ether. Pascal's message had come before I redid it.

One amplification to Pascal's message. Robert Eachus claims that you do not
need separate identification of routines, having a simple one for all
overloaded routines is sufficient. That is rubish. It is quite common in Claw
for a derived type (subtype in O-O terms) to have routines with the same name
and additional parameters. That's partially because of our minimalistic naming
(we try to name routines "Add" as opposed to "Add_Key_to_List"). In such a
case, usually the existing routine is overridden, and the new version with
additional parameters is an overriding. A single pragma which specifies one or
the other will not work in this case; using a pragma to specify "don't care"
eliminates the added safety we're trying to gain.

After all, this feature is intended to increase the safety of O-O programs
by preventing unintended changes (the most important being when a routine
which is intended to be overriding is not in fact overriding). If such
safety requires the use of lots of extra declarations (such as renamings),
or worse, changing the names of routines, it is not going to get used as
much. After all, in a perfect world, all Ada code would use these
"overridding indicators" on all subprogram declarations (which probably is
how the language should have been designed in the first place - but this
problem goes back to Ada 83 and before).

Also, solving the problem by prohibiting these on subprograms in the visible
part or some such doesn't make sense either, as most O-O types will be some
sort of private type.

I'm no longer convinced that an acceptable solution is possible for this
problem (even using syntax); there's no hope for pragmas alone.

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

From: Robert Dewar
Sent: Thursday, May 15, 2003  8:56 PM

> That's new syntax, so if we have to have new syntax we might as well do
> it right.

Actually you do not have to add new syntax, as DEC showed with its import
and export pragmas, it is perfectly possible to specify a specific
overloading in a pragma. However, it's not very attractive, so I understand
this argument, nevertheless I think pragmas are preferable. The point is
that the argument:

> That's new syntax, so if we have to have new syntax we might as well do
> it right.


is convincing but erroneous, since it rests on a false assumption.

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

From: Randy Brukardt
Sent: Thursday, May 15, 2003  8:56 PM

Fine. Feel free to make an update to the AI-00218.TXT proposal that covers
all of the issues in the Appendix to John's recent proposal.

I was the original author of the pragma proposal, and I will not work on it
further (as author, of course I'll work on it as editor), as I believe that
either John's proposal or the alternative that I've discussed privately are
better solutions. The reasons are usability and implementability. Because
the syntax is part of the subprogram declaration, the necessary checking can
(indeed, must) be done when the declaration is processed. That means that
all of the information is there to make the checking. With Janus/Ada, at
least, we figure out the overridding (or not) when we process the
declaration, assigning tag slots, then discard it all (its not stored). It
can be figured out again later, but its painful to do (and error-prone).

I also think it is more readable to use syntax for this, as it means that
the specifiers can't get separated from the subprograms.

The only question is whether syntax is too heavy. I don't think so, because
this is a significant safety issue in Ada 95. Given that we're marketing Ada
as having been designed to be safe, it is rather embarassing to have the
'wrong' routines to be called without being detected by the compiler.

(The other such issue, default initialization of scalar and array objects,
probably ought to be looked at again. But that is a case of something that
was looked at in Ada 95 and explicitly decided not to fix. So I'm not sure
of any benefit of reopening it.)

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

From: Pascal Leroy
Sent: Friday, May 16, 2003  1:39 AM

> Actually you do not have to add new syntax, as DEC showed with its import
> and export pragmas, it is perfectly possible to specify a specific
> overloading in a pragma. However, it's not very attractive, so I understand
> this argument...

One of the issues was that we didn't want to come up with something that
would look bolted-on five years from now.  Having to pepper a
specification with complicated pragmas doesn't look too appealing now,
it will be really ugly in 2008.  Of course, I realize that this is an
aesthetical argument.

The most convincing argument in favor of pragmas is that you can start
using them now, without compiler changes.  However, I'm not sure I
entirely buy this.  Once we have agreed upon a syntax, it's an afternoon
project for an implementer to add that new syntax (without any semantic
checks) to their parser.  And there are less that half-a-dozen front-end
technologies these days.  So if there is the slightest market demand for
this, syntax support can be in compilers in no time (if there is no
market demand the whole point is moot).  For any real-life project,
starting to use this feature would be a conscious decision, carefully
planned, and they might as well ask their favorite vendor for a parser
patch.

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

From: Pascal Leroy
Sent: Friday, May 16, 2003  3:37 AM

> Actually you do not have to add new syntax, as DEC showed with its import
> and export pragmas, it is perfectly possible to specify a specific
> overloading in a pragma.

I must also mention that this approach, which worked fine in Ada 83, is
not-so-straightforward in Ada 95 because of the addition of anonymous
access types.  The pragma:

   pragma Export_Function (Foo,
                           Parameter_Types  => Integer, access Boolean, Float,
                           Result_Type      => String);

does not follow the syntax rules because 2.8(3) only has name or
expression, not access_definition.  I realize that you can invent a
convention to handle this case, but it becomes quite distasteful.  Plus,
you have to remember that we consider adding anonymous
access-to-subprogram types as part of the amendment, and these types
would be intractable using a pragma without new syntax.

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

From: Robert I. Eachus
Sent: Thursday, May 15, 2003  11:39 PM

Randy Brukardt wrote:
> Pascal said:

>>We tried with pragmas.  As a matter of fact, we wrote the AI with
>>pragmas initially, for all the good reasons that were listed (again) in
>>this thread.  As a matter of fact, this AI went all the way up to WG9
>>and was approved.  It only had one minor problem: it was all wrong.
>>
>>In order to deal with complicated situations involving private types,
>>you need to be able to designate one particular subprogram among a set
>>of overloaded subprograms.  If you don't want to force users to add
>>renamings all over the place, this means that you need a way
>>to specify

> One amplification to this. Robert Eachus claims that you do not need
> separate identification of routines, having a simple one for all overloaded
> routines is sufficient. That is rubish. It is quite common in Claw for a
> derived type (subtype in O-O terms) to have routines with the same name and
> additional parameters.

I think you guys threw out the baby with the bathwater.  I said in my
initial message:

"One last point.  There is a potential problem with the pragma approach
when several declarations in the same declarative part have the same
name.  I think that the pragmas should apply to all declarations with
the same name, as most of the time that is exactly what will be desired.
(For example, if you have  several Finalize operations declared in the
same scope, it will be highly unusual to want only some of them to
override.)

"But there needs to be a way to deal with the unusual case.  I think
that I prefer that the pragma normally apply to all declarations in
scope. But if there are two or more pragmas applying to the same name,
the first should apply to declarations before its point of occurance,
and the second declaration, should apply up to the point of its
occurance and so on.  That way the pragma can be put directly after the
declaration(s) it applies to.

"But in any case, you must have all three pragmas available (or a pragma
with three arguments), independent of the default.  I prefer pragmas
Overrides, No_Overriding, and May_Override."

As far as I can see this solves all of the nasty examples that have been
given.  There are times when it looks ugly in some of the more bizzare
cases, but if multiple pragmas with the same name as an argument always
apply to all preceding subprogram declarations with that name it works.
  There are cases where this generalization of the must immediately
follow rule makes the text elegant, and it is always possible to
construct cases which require more than one pragma per explicit
subprogam name.  I consider those cases examples of bad design but that
is a  detail.  Let me show you how the examples cited by Randy and
Pascal work:

It is quite common in Claw for a derived type (subtype in O-O terms) to
have routines with the same name and additional parameters. That's
partially because of our minimalistic naming (we try to name routines
"Add" as opposed to "Add_Key_to_List").

type Widget is new ... with private;

procedure Add(W: in out Widget;...);
procedure Add(W: in out Widget;...);
procedure Add(W: in out Widget;...);
pragma Overrides(Add);

procedure Add(W: in out Widget;...);
procedure Add(W: in out Widget;...);
procedure Add(W: in out Widget;...);
pragma No_Overriding(Add);

Is that so horrible?  I could complain about all those Add operations,
but that is your design choice.  Incidently notice that at first it
seems unAdalike to have pragmas whose scope ends at the pragma.  But
once you think about what these pragmas do, it makes perfect sense.
These are assertions.  They don't change anything about the declarations
they apply to, they just check that the asserted behavior is true, and
if strict checking applies, they note that these declarations are
correct.  My proposed rule allows the pragma to appear before the
Overridings just to allow this case:

   type Foo is new Bar with private;
   pragma Overrides (Foo);

This says that all of the subprogams which become operations of Foo,
whether declared in the public part of a package or in the private part.
It is legal, but from my perspective a bit naughty to do this, then in
the private part say:

private
   function My_Create(...) return Foo;
   pragma No_Overriding(My_Create);
   ...

I think that many style guides would frown on that, but that is the
purpose of style guides, to frown appropriately. ;-)

One of the troubling cases in version 1.14 of the write-up is:

package P is
     type T is tagged private;
private
     procedure P (Y : T);
end P;

package P.C is
     type NT is new T;
     procedure P (Y : NT);
     pragma Overrides (P);   -- Could use Might_Overrides here,
                             -- so privateness is not broken.
private
     -- Overrides here P.
end P.C;

You get to choose between lying publicly, or exposing private details.
With my scheme, the appearance of the pragma can be delayed:

package P is
     type T is tagged private;
private
     procedure P (Y : T);
end P;

package P.C is
     type NT is new T;
     procedure P (Y : NT);
     --  No pragma here, so privateness is not broken.
private
     pragma Overrides (P);   -- In the private part, the
                             -- private part of P is visible
                             -- so pragma makes more sense here.
end P.C;

As for this example, I am on very shaky ground about what is wanted:

pragma Explicit_Overridding;
package P is
    type T is private;
    function "+" (Left, Right: T) return T;
    pragma Optional_Overriding("+"); -- So there is no check here.
private
    type T is range 0 .. 100;     -- "+" overrides
    function "+" (Left, Right: T) return T; -- A redeclaration.
    pragma Overrides ("+");
end P;

Apparently the assumption is that overriding behavior must be specified
even for types that are neither tagged types or derived types, and for
implicitly declared operations.  Also that there is some reason for
explicitly lying in the public part of the package declaration.  I don't
agree with any of that. If you feel it is needed how do you do it with
the changed syntax proposal?  If I am missing the point of the example
please explain it to  me.  Especially since Randy said:

"The main advantage of the pragmas only proposal was that no new syntax
or semantics (other than the check itself) is needed. That no longer
appears to be the case, so I have reluctantly abandoned this alternative
of the AI."

But if I do understand the intentions of the example, with my solution
you can put the pragma where it makes sense:

pragma Explicit_Overridding;
package P is
    type T is private;
    function "+" (Left, Right: T) return T;
    -- No pragma here.
private
    type T is range 0 .. 100;  -- "+" overrides
    -- No redeclaration here.
    pragma Overrides ("+");    -- applies to "+" in visible part
end P;

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

From: Tucker Taft
Sent: Friday, May 16, 2003  5:20 AM

There was at least one other problem, which had to do with
subprograms which were not overriding in the visible part,
but which were overriding in the private part, although the
subprogram was itself declared in the visible part.  This was
felt to be one of the final "nails" in the pragma "coffin,"
as it effectively *required* that the pragma be separated
from the subprogram spec, making the "placement" approach
to identifying one subprogram no longer sufficient.

Although we were all aware that Dec/Compaq/HP came up with a way
to allow pragmas to specify particular subprograms among
a group of overloaded subprograms, we all felt that this
problem ultimately *deserved* syntax.  Having made that decision
(now several meetings ago, though it was rehashed in Padua), we moved
on to deciding on the best syntax.

Although it is sometimes fruitful to re-open certain decisions if
there are some new insights, I haven't heard anything sufficiently
new here to justify re-opening this one.  We really have gone
through this decision process quite carefully, and we reached a
consensus.  I realize that if someone didn't attend an ARG meeting
they couldn't contribute or not contribute to such a consensus, but
that is the way these things tend to work.  Sometimes when a decision
is still tentative, it can be kept open long enough to allow
non-attendees to make some important contributions, but at least
for this one, that would have had to have been a while ago.

Now I think we should focus on the syntax, and try to get it right,
rather than swinging back around to the starting point.

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

From: Robert Dewar
Sent: Friday, May 16, 2003  6:03 AM

I must say I can't see any significant problem with Robert (Eachus) proposal,
but perhaps I am missing something.

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

From: Robert I. Eachus
Sent: Friday, May 16, 2003  9:51 AM

Robert Dewar wrote:
> I must say I can't see any significant problem with Robert (Eachus) proposal,
> but perhaps I am missing something.

I feel the same way.  I think the proposal I put on the table solves the
problems that caused the pragma approach to be dropped.  And as far as I
can see, the current synax change proposal doesn't.  So either I am
doing a bad job explaining it, or we are missing something...

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

From: Robert Dewar
Sent: Friday, May 16, 2003  6:14 AM

and they might as well ask their favorite vendor for a parser
patch.

But a "parser patch" is non-conforming, so either has to be under a special
switch, or we have to wait till the entire WG9 approval process is complete.

The pragma proposal can be implemented in a couple of hours, but of course
it's not such a good idea to do this if the ARG is still twiddling its thumbs
on the issue.

I must say I would be more receptive to the syntax proposal if there was some
decent syntax, and none of this OR NOT nonsense.

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

From: Robert Dewar
Sent: Friday, May 16, 2003  6:56 AM

> does not follow the syntax rules because 2.8(3) only has name or
> expression, not access_definition.  I realize that you can invent a
> convention to handle this case, but it becomes quite distasteful.  Plus,
> you have to remember that we consider adding anonymous
> access-to-subprogram types as part of the amendment, and these types
> would be intractable using a pragma without new syntax.

I don't see the need for new syntax to handle this case, it would seem to
be for example that integer'access would be an acceptable way of designating
such a type.

Interestingly, in GNAT we have all the DEC pragmas, and they are quite useful,
e.g. for specifying that a specific argument be passed by reference.

(obviously "quite useful" here is talking about rather specialized interface
situations :-)

That means that GNAT has a bug that we cannot differentiate in the case of
access parameters, but not too surprisingly, no one ever reported this bug :-)

I guess we should implement the type'access syntax in the context of these
pragmas. Interesting (obviously we are not about to add new syntax).

But indeed following this path for the overriding is getting unacceptably
kludgy, so the only reasonable pragma approach would be that suggested
by Robert Eachus.

I am confused at this stage on the alternative, what is the latest greatest
suggestion for concrete syntax additions to the subprogram declarations.

By the way, the implementation burden of any syntax additions is always
significant, compared to pragmas, so I strongly disgaree with Randy there.
For syntax additions, you have to make changes to coding standards documents,
pretty printers, editors that understand syntax, etc. The compiler changes are
of course trivial, but that's never where the main work is for a change to the
syntax.

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

From: Robert Dewar
Sent: Friday, May 16, 2003  7:18 AM

> Although it is sometimes fruitful to re-open certain decisions if
> there are some new insights, I haven't heard anything sufficiently
> new here to justify re-opening this one.  We really have gone
> through this decision process quite carefully, and we reached a
> consensus.  I realize that if someone didn't attend an ARG meeting
> they couldn't contribute or not contribute to such a consensus,

Consensus in such an issue can be deceiving.

After all the DR's had a very clear consensus that the syntax for what we
now call tagged types should include the word class. We voted on that and
it was a pretty close to unanimous vote.

But in practice no one came up with a syntax that people found generally
acceptable. More accurately, the prefix proposal narrowly failed because
people did not like the syntax (indeed it should really have passed, because
the Japanese delegation did not understand that by voting against it they
would lose CLASS all together, which they really preferred, if Japan had
voted positively, it would have passed 4-2).

So what happened, is that from failure to find nice syntax for CLASS, we
ended up with the peculiar keyword TAGGED, when there was a clear consensus
against it.

In this case, there is a consensus to use syntax. Sounds reasonable, I think
I would have certainly signed up to this general notion.

But then you have to come up with actual syntax, and if that actual syntax
includes OR NOT, all I can say is that I find this as ugly as Tucker found
the prefix CLASS syntax :-)

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

From: Tucker Taft
Sent: Friday, May 16, 2003  7:23 AM

Robert Dewar wrote:
 > ...
> I am confused at this stage on the alternative, what is the latest greatest
> suggestion for concrete syntax additions to the subprogram declarations.

For the basic case of overriding outside of a generic,
we have pretty much settled on:

   overriding
   procedure Blah(...);

This can be used in a private part, even if the subprogram
is declared in the visible part, to indicate that the subprogram
is overriding a privately-inherited operation.

There is a configuration pragma (usable either library-wide or
per source file) which specifies that the default
is non-overriding.  In the absence of the pragma, the
default is might or might not override (i.e. the current
rule).

What remains under debate is how to handle the case in
a generic where the operation doesn't override in the
generic, but it might or might not override in the instance.
John proposed "overriding or not" as a way of allowing
overriding in the instance.  I have countered with
requiring the explicit use of "not overriding" in the
(presumably rare) cases where you want to disallow overriding
in the instance.  In the absence of explicit "not overriding",
the default would be no additional check in the instance.
As part of this, I would allow an explicit "not overriding"
anywhere, as a way to be explicit, and to avoid any
reliance on a configuration pragma's presence.

Obviously this debate is still underway, and input on
*this* issue would be very timely ;-)

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

From: Pascal Leroy
Sent: Friday, May 16, 2003  10:01 AM

> type Widget is new ... with private;
>
> procedure Add(W: in out Widget;...);
> procedure Add(W: in out Widget;...);
> procedure Add(W: in out Widget;...);
> pragma Overrides(Add);
>
> procedure Add(W: in out Widget;...);
> procedure Add(W: in out Widget;...);
> procedure Add(W: in out Widget;...);
> pragma No_Overriding(Add);

An approach like that was considered and rejected because we want people
to be able to add overriding indicators to existing code relatively
easily, and here they would have to reorder declarative parts which may
be quite large.  Not only is that a lot of error-prone work, but it
creates lots of spurious differences in versions control systems.

Of course you could use the pragmas to delimit very small regions,
containing only one or two subprograms, but that starts to look like
C++, only uglier.

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

From: Robert I. Eachus
Sent: Friday, May 16, 2003  1:01 PM

Pascal Leroy wrote:

 > An approach like that was considered and rejected because we want
 > people to be able to add overriding indicators to existing code
 > relatively easily, and here they would have to reorder declarative
 > parts which may be quite large.  Not only is that a lot of
 > error-prone work, but it creates lots of spurious differences in
 > versions control systems.

I would rather say that it MAY result in a large number of changes in
some cases.  But the syntax approach requires changing every one of the
potentially overloading declarations.

 > Of course you could use the pragmas to delimit very small regions,
 > containing only one or two subprograms, but that starts to look like
 > C++, only uglier.

I agree with the aesthetics issue.  The question becomes when will the
pragma approach get ugly.  For my code, one or two pragmas per derived
tagged type is much preferrable to changing every subprogram
declaration.  Others have different styles, as Randy explained, and I
understand that.

However, I still have yet to see how the current proposal solves the
original problem.  That is what really concerns me.  Adding all the
extra scaffolding of extra program declarations to me doesn't solve the
original problem.  For example:

with Ada.Finalization;
package Root is
     type Root_Type is tagged private;
     procedure Do_Something (Object : in out Root_Type;
                             Data : in Natural);
private
     type Root_Type is new Ada.Finalization.Controlled with null record;
     not overriding
     procedure Do_Something (Object : in out Root_Type;
                             Data : in Natural);
     -- additional declaration required by new rules.
     overriding
     procedure Finalize (Object : in out Root_Type); -- 2
     -- Finalization hidden in private part to since Controlled is
     -- hidden.
end Root;

with Root;
package Leaf is
    type Derived_Type is new Root.Root_Type with null record;
    overriding
    procedure Do_Something (Object : in out Derived_Type;
                            Data : in Boolean); -- 1
    not overriding
    procedure Finalise (Object : in out Derived_Type);
         -- Note: Alternative spelling of "Finalize".
         -- and note that in the public view it is not overriding.
end Leaf;

with Leaf;
procedure Sample is
      Obj : Leaf.Derived_Type;
begin
      Leaf.Do_Something (Obj, 10); -- Calls (1).
      -- Finalization of Obj will call (2).
end Sample;

-- Click BOOM!

If you prefer, make the procedure Finalise a generic instantiation so
that no declaration is needed in the body. So now we not only have the
same old problem but I have to go to all that trouble to sign my own
death warrant.  This is the problem I see with ANY solution that
requires the overriding/non overriding declaration to located with the
original declaration.

Let's get a bit more heavy handed.  Require that if a type is private,
that if a type is derived from it there has to be a private part in the
package and a re-declaration of any overriding subprogams there:


with Root;
package Leaf is
    type Derived_Type is new Root.Root_Type with null record;
    overriding
    procedure Do_Something (Object : in out Derived_Type;
                            Data : in Boolean);
    not overriding
    procedure Finalise (Object : in out Derived_Type);
         -- Note: Alternative spelling of "Finalize".
         -- and note that in the public view it is not overriding.
private
    overriding
    procedure Finalize (Object : in out Derived_Type);
    -- Whoops, no error message on the body because this time I spelled
    -- Finalize right.  But at least even if the original declaration of
    -- Finalise is a generic instantiation, I'll get an error message
    -- when compiling the body, or when I don't provide one.
end Leaf;

With my approach you will always get an error message on the package
specification.  It may be a pretty confusing one if you have:


with Root;
package Leaf is
    type Derived_Type is new Root.Root_Type with null record;
    pragma Overriding(Derived_Type);

    procedure Do_Something (Object : in out Derived_Type;
                            Data : in Boolean);
    procedure Finalise (Object : in out Derived_Type);
         -- Note: Alternative spelling of "Finalize".
         -- and note that in the public view it is not overriding.
end Leaf;

But you will always get one.  If you use:

    pragma Overriding(Do_Something, Finalize);

The error you will get will depend on how you spell the name in the
pragma.  But at least you will get something.

The reason I am so sensitive about getting an error message on the
specification is that on large development projects, the specification
may be written and agreed to months before there is a body.

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

From: Tucker Taft
Sent: Friday, May 16, 2003  2:05 PM

Robert I. Eachus wrote:
 > ...
> However, I still have yet to see how the current proposal solves the
> original problem.  That is what really concerns me.  Adding all the
> extra scaffolding of extra program declarations to me doesn't solve the
> original problem.

I'm afraid with all the to'ing and fro'ing, I have lost track
of what is your "original problem."  If it is reflected in
what comes below, I don't see a problem.


For example:
>
> with Ada.Finalization;
> package Root is
>     type Root_Type is tagged private;
>     procedure Do_Something (Object : in out Root_Type;
>                             Data : in Natural);
> private
>     type Root_Type is new Ada.Finalization.Controlled with null record;
>     not overriding
>     procedure Do_Something (Object : in out Root_Type;
>                             Data : in Natural);
>     -- additional declaration required by new rules.
>     overriding
>     procedure Finalize (Object : in out Root_Type); -- 2
>     -- Finalization hidden in private part to since Controlled is
>     -- hidden.
> end Root;
>
> with Root;
> package Leaf is
>    type Derived_Type is new Root.Root_Type with null record;
>    overriding
>    procedure Do_Something (Object : in out Derived_Type;
>                            Data : in Boolean); -- 1
>    not overriding
>    procedure Finalise (Object : in out Derived_Type);
>         -- Note: Alternative spelling of "Finalize".
>         -- and note that in the public view it is not overriding.
> end Leaf;
>
> with Leaf;
> procedure Sample is
>      Obj : Leaf.Derived_Type;
> begin
>      Leaf.Do_Something (Obj, 10); -- Calls (1).
>      -- Finalization of Obj will call (2).
> end Sample;
>
> -- Click BOOM!

I have lost you here.  If a type is not *visibly* controlled
somewhere within the immediate scope where the derived type is
declared, there is no way you can override the Finalize operation,
any way you spell it. See 7.3.1(6/1).

> If you prefer, make the procedure Finalise a generic instantiation so
> that no declaration is needed in the body. So now we not only have the
> same old problem but I have to go to all that trouble to sign my own
> death warrant.  This is the problem I see with ANY solution that
> requires the overriding/non overriding declaration to located with the
> original declaration.

I still don't understand the problem.  We don't require
the "overriding" annotation be on the original declaration.
We allow an additional (re)declaration to be given in the
private part if that is where the operation "becomes"
an overriding. Below you have chosen to use "not overriding"
explicitly, but that seems gratuitous, especially in this
situation where you will be giving a contradictory (and wrong,
given 7.3.1(6/1) annotation in the private part.  If we do
allow the explicit "not overriding" I might be tempted to
disallow it in a case where it becomes overriding in the
private part, somewhat analogous to the suggestion for
leaving it out in a generic when it might become overriding
in the instance.


> Let's get a bit more heavy handed.  Require that if a type is private,
> that if a type is derived from it there has to be a private part in the
> package and a re-declaration of any overriding subprogams there:
>
>
> with Root;
> package Leaf is
>    type Derived_Type is new Root.Root_Type with null record;
>    overriding
>    procedure Do_Something (Object : in out Derived_Type;
>                            Data : in Boolean);
>    not overriding
>    procedure Finalise (Object : in out Derived_Type);
>         -- Note: Alternative spelling of "Finalize".
>         -- and note that in the public view it is not overriding.
> private
>    overriding
>    procedure Finalize (Object : in out Derived_Type);
>    -- Whoops, no error message on the body because this time I spelled
>    -- Finalize right.  But at least even if the original declaration of
>    -- Finalise is a generic instantiation, I'll get an error message
>    -- when compiling the body, or when I don't provide one.
> end Leaf;

This would get an error message because you can't override
something you never have visibility on, per 7.3.1(6/1).  That would
break "privateness."

Perhaps you need to reconstruct your example, but as of
now, I don't see the problem.


>
> With my approach you will always get an error message on the package
> specification.

This is nice, I suppose, but this example at least doesn't
illustrate your point, and the advantage of having the
error on the spec is pretty small, in my view at least.
(And I have worked on some pretty big Ada systems...)

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

From: Robert I. Eachus
Sent: Friday, May 16, 2003  6:42 PM

Tucker Taft wrote:

> I have lost you here.  If a type is not *visibly* controlled
> somewhere within the immediate scope where the derived type is
> declared, there is no way you can override the Finalize operation,
> any way you spell it. See 7.3.1(6/1).

Now my head really hurts!  Are you saying that the original derived
Finalize declaration really can't be overridden and that in this case
(or in this case with Finalize spelled right) dispatching still calls
the implicit operation?  I hope not, and that this is just semantics.

Let me create a better example (in current Ada):

  with Ada.Finalization;
  package Root is
    type Root_Type is tagged private;
    function Value (Object : Root_Type) return Integer;
    procedure Set (Object : in out Root_Type; Value: in Integer);
  private
     type Root_Type is new Ada.Finalization.Controlled with record
       Init_Case: Integer := 3; end record;
    procedure Initialize (Object : in out Root_Type); -- 1
    -- Finalization hidden in private part to since Controlled is
    -- hidden.
  end Root;

  package body Root is
    function Value (Object : Root_Type) return Integer
    is begin return Object.Init_Case; end Value;

    procedure Set (Object : in out Root_Type; Value: in Integer) is
    begin Object.Init_Case := Value; end Set;

    procedure Initialize (Object : in out Root_Type) is
    begin Object.Init_Case := 1; end Initialize;

  end Root;

  with Root;
  package Leaf is
    type Derived_Type is new Root.Root_Type with null record;
    -- derived type is known to be tagged but not controlled.
    procedure Initialize (Object : in out Derived_Type); -- 2
    -- Tucker says this is not overriding right?
  end Leaf;

  package body Leaf is
    procedure Initialize (Object : in out Derived_Type)
    is begin Set(Object, 2); end Initialize;
  end Leaf;

  with Leaf;
  with Ada.Text_IO; use Ada.Text_IO;
  procedure Sample is
       Obj : Leaf.Derived_Type; -- Which Initialize gets called?
  begin
    case Leaf.Value(Obj) is
    when 1 => Put_Line(" Root.Initialize Called.");
    when 2 => Put_Line(" Leaf.Initialize Called.");
    when 3 => Put_Line(" No initialization!");
    when others => Put_Line(" I give up!");
    end case;
  end Sample;

E:\Ada\Test\AI-218>sample
  Leaf.Initialize Called.

At least GNAT agrees with me. ;-)  Seriously I think that Tucker may be
correct, "by the book."  But to not be able to declare Leaf.Initialize
as overriding defeats the whole point.  Sigh.  So now even if we adopt
my solution or the new syntax, we still have to change 7.3.1 to get the
definition of overriding to agree with the commonsense definition.

> I still don't understand the problem.  We don't require
> the "overriding" annotation be on the original declaration.
> We allow an additional (re)declaration to be given in the
> private part if that is where the operation "becomes"
> an overriding. Below you have chosen to use "not overriding"
> explicitly, but that seems gratuitous, especially in this
> situation where you will be giving a contradictory (and wrong,
> given 7.3.1(6/1) annotation in the private part.  If we do
> allow the explicit "not overriding" I might be tempted to
> disallow it in a case where it becomes overriding in the
> private part, somewhat analogous to the suggestion for
> leaving it out in a generic when it might become overriding
> in the instance.

The first part certainly makes me happy.  I don't have to lie, I am just
allowed to.  But we still have the problem.  If I go to my example above
  and declare Leaf.Initialize, (or worse Leaf.Initialise) where can I
declare it to be overriding?

If my example makes your head hurt as much as mine does now, I
apologize.  But I can now see why Tucker and I have been sparring at
cross purposes.  In the example above, the compiler and author know that
Leaf.Initialize is overriding (in the normal sense of the term) and that
it will get called--by magic if you want to think of it that way--when
an object of Leaf.Derived_Type is created.  My understanding has always
been that the intention of this AI was to make that agreement between
author and compiler explicit.  This will not only help insure that the
author does in fact know what is going on, but will make it easier for
readers to understand as well.

But if ARM overriding does not have the commonly accepted meaning, then
whether we go with a pragma or a syntax change to enforce that
definition, in can only confuse the user.

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

From: Randy Brukardt
Sent: Friday, May 16, 2003  11:06 PM

Robert Eachus wrote:

> Let me create a better example (in current Ada):
...
> E:\Ada\Test\AI-218>sample
>   Leaf.Initialize Called.
>
> At least GNAT agrees with me. ;-)

I tried this on Janus/Ada 3.1.2, ObjectAda 7.2, and GNAT 3.15a1. GNAT does
as you say (which is clearly wrong), and Janus/Ada and ObjectAda clearly say
   "Root.Initialize Called"
which is right.

> Seriously I think that Tucker may be
> correct, "by the book."  But to not be able to declare Leaf.Initialize
> as overriding defeats the whole point.  Sigh.  So now even if we adopt
> my solution or the new syntax, we still have to change 7.3.1 to get the
> definition of overriding to agree with the commonsense definition.

You're advocating the complete destruction of privateness, which you cannot
mean. Clients of Root.Root_Type (including all of Leaf) do not know that
Root_Type is controlled. Allowing them to override Initialize (on operation
that the type does not have unless you peek into the private part) is a
serious breach of privacy. So it's the case that Initialize is never
overridding in your example, and declaring it to be so would be an error
(precisely the sort of bug that this extra syntax is intended to detect).
That means GNAT has a bug here, but we don't (in general) want to base the
language rules on compiler bugs.

Now, if Leaf was a child of Root (Root.Leaf), then the situation is
completely different, and perhaps that is the case that you meant. In that
case, the overridding occurs in the private part, and you would need to put
the overriding clause in the private part.

...
> But we still have the problem.  If I go to my example above
>   and declare Leaf.Initialize, (or worse Leaf.Initialise) where can I
> declare it to be overriding?

Nowhere, because it is never overridding.

If you had Root.Leaf instead, you declare it to be overridding in the
private part. No problem. There are even cases where you'd have to do that
in the body. Ugly, but correct.

> If my example makes your head hurt as much as mine does now, I
> apologize.

It only hurts because you seem willing to discard privateness, and I doubt
that you meant to do that.

> But I can now see why Tucker and I have been sparring at
> cross purposes.  In the example above, the compiler and author know that
> Leaf.Initialize is overriding (in the normal sense of the term) and that
> it will get called--by magic if you want to think of it that way--when
> an object of Leaf.Derived_Type is created.

And the compiler has a bug, and the author is wrong. We HOPE that an error
is detected in this case! This is precisely the sort of problem that AI-218
was invented to solve, and I think your mistake here (and GNAT's)
demonstrates nicely why this AI is important: the code may do silently do
something other than is intended in a very subtle way.

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

From: Pascal Leroy
Sent: Saturday, May 17, 2003  3:20 AM

Randy reported:

> I tried this on Janus/Ada 3.1.2, ObjectAda 7.2, and GNAT 3.15a1. GNAT does
> as you say (which is clearly wrong), and Janus/Ada and ObjectAda clearly say
>    "Root.Initialize Called"
> which is right.

Apparently Randy is still unable to run Apex.  For the record, Apex says
"Root.Initialize Called" too, so there is consensus that the bug is in
GNAT.  I am surprised that this case is not checked by the ACATS, btw,
as it seems like a pretty serious issue.

> You're advocating the complete destruction of privateness, which you
> cannot mean.

Right, I nearly had a heart attack when I read Eachus' message.

> I think your mistake here (and GNAT's)
> demonstrates nicely why this AI is important: the code may do silently do
> something other than is intended in a very subtle way.

I find it frightening that there may be code out there that depends on
the GNAT behavior, and will behave differently when ported to another
compiler (or when the ACT folks fix GNAT).  This is certainly a very
strong justification for pursuing this AI.

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

From: Robert I. Eachus
Sent: Saturday, May 17, 2003  11:22 AM

Pascal Leroy wrote:

> Apparently Randy is still unable to run Apex.  For the record, Apex says
> "Root.Initialize Called" too, so there is consensus that the bug is in
> GNAT.  I am surprised that this case is not checked by the ACATS, btw,
> as it seems like a pretty serious issue.

> Right, I nearly had a heart attack when I read Eachus' message.

Well at least since I was NOT surprised by GNAT's behavior, and expected
it you can see why we have been arguing at cross-purposes.

> I find it frightening that there may be code out there that depends on
> the GNAT behavior, and will behave differently when ported to another
> compiler (or when the ACT folks fix GNAT).  This is certainly a very
> strong justification for pursuing this AI.

No disagreement at all. But for the record what happens on the other
compilers if:

1) Root.Initialize is declared publicly, although Root_Type is still
private?

2) Leaf is a child of Root, but with a priavte part--which could
possibly have nothing in it related to Derived_Type?

3) package Leaf is a child of Root, but still without a private part?

4) Same as above, but Initialize is declared by instantiating a generic
subprogram from Root, so that Root.Leaf doesn't have a body either.

5) The body of Root has a with clause for Leaf, but Leaf is not a child
of Root.

I think my understanding now is:

1) Leaf.Initialize called, since it is overriding, although Root_Type is
not visibly Controlled.

2) Leaf.Initialize is called.

3 & 4) Leaf.Initialize is also called. The AARM says: 7.3.1 (7.r) For
all of these rules, implicit private parts and bodies are assumed as needed.

5) Root.Initialize is called.  Anything else would be just too baroque.

We definitely need this AI, and my reason for strongly favoring the
pragma version now is that I need it with the GNAT bugfix.  It goes
without saying that I have programs that depend on the current GNAT
behavior.  I don't yet know if any will be broken by fixing the bug.
(Other than this test case of course.)  Most should still be correct
because tbey are the child package case, but I'd have to look.

And of course, for non-experts who may not even know what the AARM is or
where to find it, getting AI-218 implemented soonest is extremely
important.  If language lawyers and compilers have trouble understanding
the current rules (with AI-33 8652/0019 of course) non-experts will have
no clue what to expect in these corner cases.

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

From: Pascal Leroy
Sent: Monday, May 19, 2003  8:37 AM

Robert E. asked:

> 1) Root.Initialize is declared publicly, although Root_Type is still
> private?

Leaf.Initialize Called.

Now that Leaf knows that Root_Type has a primitive Initialize, it can
override it.

> 2) Leaf is a child of Root, but with a private part--which could
> possibly have nothing in it related to Derived_Type?
> 3) package Leaf is a child of Root, but still without a private part?

Not sure exactly what you mean here.  If Leaf is a child of Root,
Root.Initialize is declared in the private part, and Leaf.Initialize is
declared in the visible part then:

Leaf.Initialize Called.

That's because, when you come to the private part of Leaf you discover
that the parent type had a primitive Initialize, and overriding happens
at this point.

> 4) Same as above, but Initialize is declared by instantiating a generic
> subprogram from Root, so that Root.Leaf doesn't have a body either.

No bearing on the results, the fact that the primitive operation is
declared by a normal subprogram or by an instantiation doesn't affect
overriding.

> 5) The body of Root has a with clause for Leaf, but Leaf is not a
child
> of Root.

The with clause doesn't affect overriding, so assuming that
Root.Initialize is declared in the private part:

Root.Initialize Called.

> It goes
> without saying that I have programs that depend on the current GNAT
> behavior.  I don't yet know if any will be broken by fixing the bug.
> (Other than this test case of course.)  Most should still be correct
> because tbey are the child package case, but I'd have to look.

Yes, I guess that in most cases the derivation hierarchy will mimic the
unit hierarchy, so the right thing will happen.  Your example is pretty
uncommon in this respect.

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


Questions? Ask the ACAA Technical Agent