Version 1.2 of ais/ai-00396.txt

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

!standard 3.9.4(10/2)          05-01-27 AI95-00396/01
!class amendment 05-01-25
!status work item 05-01-25
!status received 05-01-25
!priority High
!difficulty Easy
!subject The "no hidden interfaces" rule
!summary
(See proposal.)
!problem
The "no hidden interfaces" rule of 3.9.4(10/2) is overly zealous. It should be allowed to hide interfaces when the partial view is untagged. Also, the justification for this rule in the AARM is obscure.
!proposal
Allow an untagged partial view to be complete by a tagged type that implements some interfaces. Also improve the AARM justification.
!wording
Replace 3.9.4(10/2) by:
A full view shall only be a descendant of an interface type if the corresponding partial view (if any) is untagged or is also a descendant of the interface type.
AARM Note:
Reason: Consider the following example:
package P is package Pkg is type Ifc is interface; procedure Foo (X : Ifc) is abstract; end Pkg;
type Parent_1 is tagged null record;
type T1 is new Parent_1 with private; private type Parent_2 is new Parent_1 and Pkg.Ifc with null record; procedure Foo (X : Parent_2); -- Foo #1
type T1 is new Parent_2 with null record; end P;
with P; package P_Client is type T2 is new P.T1 and P.Pkg.Ifc with null record; procedure Foo (X : T2); -- Foo #2 X : T2; end P_Client;
with P_Client; package body P is ...
procedure Bar (X : T1'Class) is begin Pkg.Foo (X); -- should call Foo #1 or an override thereof end;
begin Pkg.Foo (Pkg.Ifc'Class (P_Client.X)); -- should call Foo #2 Bar (T1'Class (P_Client.X)); end P;
If this example were legal (it is illegal because the completion of T1 is descended from an interface that the partial view is not descended from), T2 would implement Ifc twice. Once in the visible part of P, and once in the visible part of P_Client. We would need to decide how Foo #1 and Foo #2 relate to each other. There are two options: either Foo #2 overrides Foo #1, or it doesn't.
If Foo #2 overrides Foo #1, we have a problem because the client redefines a behavior that it doesn't know about, and we try to avoid this at all costs, as it would lead to a breakdown of whatever abstraction was implemented. If the abstraction didn't expose that it implements Ifc, there must be a reason, and it should be able to depend on the fact that no overriding takes place in clients. Also, during maintenance, things may change and the full view might implement a different set of interfaces. Furthermore, the situation is even worse if the full type implements another interface Ifc2 that happens to have a conforming Foo (otherwise unrelated, except for its name and profile).
If Foo #2 doesn't override Foo #1, there is some similarity with the case of normal tagged private types, where a client can declare an operation that happens to conform to some private operation, and that's OK, it gets a different slot. The problem here is that T2 would implement Ifc in two different ways, and through conversions to Ifc'Class we could end up with visibility on these two different implementations. This is the "diamond inheritance" problem of C++ all over again, and we would need some kind of a preference rule to pick one implementation. We don't want to go there (if we did, we might as well provide full-fledged multiple inheritance).
Note that there wouldn't be any difficulty to implement the first option, so the restriction is essentially methodological. The second option might be harder to implement, depending on the language rules that we would choose.
End AARM Note.
!discussion
(See proposal.)
!example
--!corrigendum
!ACATS test
An ACATS C-Test should be created to test that an untagged private type can be completed with a type that has interfaces.
!appendix

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

Questions? Ask the ACAA Technical Agent