Version 1.4 of ais/ai-10218.txt

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

!standard 8.3(26)          03-04-28 AI95-00218-02/04
!class amendment 00-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 torenamings 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 aderivation 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.

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



Questions? Ask the ACAA Technical Agent