From stt@dsd.camb.inmet.com Thu Aug 22 10:25:25 1996 Return-Path: Received: from inmet.camb.inmet.com by dsd.camb.inmet.com (4.1/SMI-4.1) id AA10445; Thu, 22 Aug 96 10:25:25 EDT Received: from sw-eng.falls-church.va.us (ns1.sw-eng.falls-church.va.us) by inmet.camb.inmet.com (4.1/SMI-4.1) id AA26459; Thu, 22 Aug 96 10:25:39 EDT Received: from dsd.camb.inmet.com by sw-eng.falls-church.va.us (8.7.1/) id OAA15924; Thu, 22 Aug 1996 14:23:49 GMT Received: from henning.camb.inmet.com.i2ada by dsd.camb.inmet.com (4.1/SMI-4.1) id AA10442; Thu, 22 Aug 96 10:24:46 EDT Date: Thu, 22 Aug 96 10:24:46 EDT From: stt@dsd.camb.inmet.com (Tucker Taft) Message-Id: <9608221424.AA10442@dsd.camb.inmet.com> To: 100071.47@CompuServe.COM, ada-comment@sw-eng.falls-church.va.us Subject: Re: Controversial visibility of inherited private components in a child unit private part (or body) !topic Controversial visibility of inherited private components ... !reference RM95 7.3 (15) 7.3.1 (3) 7.3.1 (10) !reference 96-5635.a Bernard Maudry 96-08-21 !from Tucker Taft 96-08-22 !keywords visibility inherited private components child <> !discussion > I would like to know if the following code is legal or not as 2 of the 4 > compilers I use think that it is illegal. I will not try to explain > you the problem as you will better understand it when reading the code below. [Well, reading the code that appeared below was a bit tricky, given that it ended up as one long line. I have reformatted it below.] package Top is type Node is abstract tagged private ; private type Node is abstract tagged record Name : Integer := 0; end record; end Top ; package Top.Mid is type Node is abstract new Top.Node with private ; private type Node is abstract new Top.Node with record Kind : Integer := 0; end record; end Top.Mid ; with Top.Mid; generic type Parent is abstract new Top.Mid.Node with private; package Top.Extra is type Node is abstract new Parent with null record ; end Top.Extra ; with Top.Mid; with Top.Extra; package Top.Mid.Extra is new Top.Extra (Parent => Top.Mid.Node); with Top.Mid.Extra ; package Top.Mid.Bot is type Node is new Top.Mid.Extra.Node with null record ; The_Node : Node ; private -- The legality of the two following lines of code is controversial. -- Of 4 Ada95 compilers, 2 of them think they are legal, and the 2 others -- reject them as illegal. -- Where is the truth ? Why ? Buggy_1 : Integer := The_Node.Name; Buggy_2 : Integer := The_Node.Kind; -- NOTE: I have added the following two lines: Not_Buggy_1 : Integer := Top.Mid.Node(The_Node).Name; Not_Buggy_2 : Integer := Top.Mid.Node(The_Node).Kind; end Top.Mid.Bot ; ======================== The compilers that declare the lines Buggy_1 and Buggy_2 illegal are operating correctly. If you want visibility on Name and Kind you will have to convert the type to Top.Mid.Node, as illustrated in Not_Buggy_1 and _2. There is a general rule that you can never have more visibility into the components or operations of a type that in the package where the type is declared. Effectively, the components and operations of a type are "frozen" to be those visible somewhere within the "immediate" scope of the type. Even if you go into a package that knows more about the ancestors of the type, that doesn't change the set of components or primitives that the type has. So in the above case, the type Top.Mid.Extra.Node is declared in an instance of Top.Extra, where there is no visibility on the Name or Kind components of the immediate parent type (Top.Mid.Node), and hence these components are not inherited. This is despite the fact that it *is* visible that Top.Mid.Node is derived from Top.Node, and it *is* visble (inside the implicit private part of Top.Extra) that Top.Node has a "Name" component. If you want these components to be inherited, then the generic needs to be a child of Top.Mid. Even then, only within the private part and body of the generic itself, or within the private part or body of a child of the generic, will these extra components be visible. Alternately, as illustrated above, you can take advantage of the fact that these types are visibly derived from Top.Mid.Node, to convert to Top.Mid.Node and gain visibility on the extra components in that manner. This paradox of knowing the ancestry of a type, but not being able to take advantage of it except through explicit conversion, also applied to derived types in Ada 83. It is based on the general notion that even inherited operations and components need to have a point of declaration, and that point of declaration is required to be in the immediate scope of the derived type. If there is no place where such implicit declarations could occur, then the corresponding operations or components are not inherited. This is discussed in some depth in RM95-7.3.1, and if you have it, in AARM95-7.3.1(7.a-7.r). -Tuck From stt@dsd.camb.inmet.com Thu Aug 22 10:38:33 1996 Return-Path: Received: from inmet.camb.inmet.com by dsd.camb.inmet.com (4.1/SMI-4.1) id AA10609; Thu, 22 Aug 96 10:38:33 EDT Received: from sw-eng.falls-church.va.us (ns1.sw-eng.falls-church.va.us) by inmet.camb.inmet.com (4.1/SMI-4.1) id AA26646; Thu, 22 Aug 96 10:38:47 EDT Received: from dsd.camb.inmet.com by sw-eng.falls-church.va.us (8.7.1/) id OAA16337; Thu, 22 Aug 1996 14:36:59 GMT Received: from henning.camb.inmet.com.i2ada by dsd.camb.inmet.com (4.1/SMI-4.1) id AA10600; Thu, 22 Aug 96 10:37:58 EDT Date: Thu, 22 Aug 96 10:37:58 EDT From: stt@dsd.camb.inmet.com (Tucker Taft) Message-Id: <9608221437.AA10600@dsd.camb.inmet.com> To: ada-comment@sw-eng.falls-church.va.us, pleroy@Rational.COM Subject: Re: Anonymous access types and finalization Cc: swb@rational.com !topic Anonymous access types and finalization !reference RM95 3.10(2) !reference RM95 3.7(27) !reference RM95 7.6.1(11) !reference RM95 3.10.2(12) !reference 96-5633.a Pascal Leroy 96-08-20 !from Tucker Taft 96-08-22 <> !discussion > The finalization of an object created by an allocator occurs when the master > of the ultimate ancestor of the access type is left, as stated in 7.6.1(11). > In the case of access discriminants, 3.10(2) tells us that "an > access_definition defines an anonymous access type"; I take this to imply that > an anonymous access type is an "ultimate ancestor" in the sense of 7.6.1(11). > In addition, 3.7(27) tells us that "an access_definition is elaborated when > the value of a corresponding access discriminant is defined"; I take this to > imply that the master of the anonymous access type is the master that > elaborated the discriminant constraint. Not quite. The accessibility level determines the lifetime for the purposes of finalization. For access discriminants, the accessibility level is defined by RM95-3.10.2(12): The accessibility level of the anonymous access type of an access discriminant is the same as that of the containing object or associated constrained subtype. > The interaction of these rules has the unfortunate consequence that it makes > it possible to reference an object after it has been finalized, as shown in > the following example: This is not a problem, given 3.10.2(12). > procedure P1 is > type T (D : access Some_Controlled_Type) is ... ; > > procedure P2 is > type T_Ref is access T; > > X : T_Ref; > > procedure P3 is > begin > X := new T (D => new Some_Controlled_Type); > -- (1) > end P3; > begin > P3; > -- (2) > end P2; > begin > P2; > end P1; > > The discriminant constraint for the allocated object X.all is elaborated by > P3. The elaboration of this constraint also elaborates the access_definition, > therefore, the master of the anonymous access type is P3. So when leaving P3, > at the point marked (1), the allocated object X.all.D.all is finalized, as per > 7.6.1(11). But of course, after leaving P3 we can still use the name > X.all.D.all to reference this object (at the point marked (2)), and this is > bad... > > It seems to me that we need a rule that says that the master of an anonymous > access type A used in the specification of an access discriminant in type T, > the master of A is the master of T, not the master that caused A to be > elaborated. Or, alternatively, that when an allocator is used as a > discriminant value for an anonymous access type, the master of the allocated > object is defined to be the master of the discriminated object. (These two > proposals are different, but they both seem to cure the problem, although the > first one is probably easier to implement.) As specified by 3.10.2(12), the accessibility level associated with the nested allocator "new Some_Controlled_Type" is the same as that of the enclosing object, X.all, which is the same as T_Ref. The master is hence P2, and the finalization for the nested allocator should be performed when exiting P2. > Pascal Leroy +33.1.30.12.09.68 > pleroy@rational.com +33.1.30.12.09.66 FAX -Tuck From stt@dsd.camb.inmet.com Thu Aug 22 11:02:09 1996 Return-Path: Received: from inmet.camb.inmet.com by dsd.camb.inmet.com (4.1/SMI-4.1) id AA10838; Thu, 22 Aug 96 11:02:09 EDT Received: from sw-eng.falls-church.va.us (ns1.sw-eng.falls-church.va.us) by inmet.camb.inmet.com (4.1/SMI-4.1) id AA27123; Thu, 22 Aug 96 11:02:24 EDT Received: from dsd.camb.inmet.com by sw-eng.falls-church.va.us (8.7.1/) id PAA16832; Thu, 22 Aug 1996 15:00:36 GMT Received: from henning.camb.inmet.com.i2ada by dsd.camb.inmet.com (4.1/SMI-4.1) id AA10835; Thu, 22 Aug 96 11:01:35 EDT Date: Thu, 22 Aug 96 11:01:35 EDT From: stt@dsd.camb.inmet.com (Tucker Taft) Message-Id: <9608221501.AA10835@dsd.camb.inmet.com> To: ada-comment@sw-eng.falls-church.va.us, pleroy@Rational.COM Subject: Re: Profile of predefined operators Cc: swb@rational.com !topic Profile of predefined operators !reference AI95-00145 !reference RM95-4.5.2(7-9) !reference RM95-8.5.4(5) !reference 96-5634.a Pascal Leroy 96-08-20 !from Tucker Taft 96-08-22 <> !discussion > The referenced AI didn't trigger a lot of discussions, to say the least, so > let me try again... > > There are two other issues related to the question of the profile of > predefined operators. One is the interaction with the contract model, the > other is the fact that it is impossible to write a specification for the > predefined operators of composite types. > > As an example of the first issue, look at the following example: > > generic > type T is (<>); > package P is > function F (L, R : T) return Boolean; > end P; > > package body P is > function F (L, R : T'Base) return Boolean renames "="; -- (1) > function F (L, R : T) return Boolean renames "="; -- (2) > end P; > > Which (if any) of the declarations (1) and (2) is legal? Neither, since the predefined operators are of convention Intrinsic, and renaming-as-body is not permitted for convention Intrinsic, unless the renaming occurs before the freezing point of the corresponding subprogram spec. See 8.5.4(5). > ... If we follow 4.5, > which seems to say that the predefined operators are parameters of the > (unconstrained) type, then (1) is legal and (2) is illegal. If we follow the > declarations given in the specification of Standard (A.1(7)) then we should > use (1) if T happens to be an enumeration type, and (2) if T happens to be an > integer type. I presume you have your (1)'s and (2)'s inverted. In any case, the declarations given in A.1 for the operators of Boolean are wrong. They should use Boolean'Base for the operands. This is because RM95 4.5.2(7-9) and elsewhere use an italicized "T" to give the formal parameter subtype. This notation is meant to be the unconstrained subtype, which for scalars is denoted T'Base. > ... Of course, since the body of a generic is compiled in an > "assume-the-worst" manner, neither (1) nor (2) is legal. This is a nuisance. > > In the rest of this discussion I assume that the intended meaning is that of > 4.5, and that A.1(7) is a mistake. Correct. > Consider now what happens if we change the formal part of P to be: > > generic > type T is private > package P is ... > > Then we cannot even write (1), because the attribute 'Base is not available > for a composite type. And of course (2) doesn't make sense: > > type T is array (1 .. 10) of Character; > -- This type has an operator "=", but its profile is certainly not: > -- function "=" (Left, Right : T) return Boolean; > -- So we just cannot write that profile in Ada. Sigh. > > This situation is quite unpleasant, because a renaming-as-body would be very > useful in this case. I'm not convinced about this, given that the "renaming-as-body" would have to appear before the function being declared is frozen. > Clearly, similar difficulties arise with private types, at places that have > visibility over the private view: > > package P is > type T is private; > function Foo1 (L, R : T) return Boolean; > function Foo1 (L, R : T) return Boolean renames "="; -- legal? This is certainly a legitimate question, though again, since the renaming-as-body has to occur before freezing, you could pretty much just use the renaming-as-spec and avoid the issue. I would say that the current rules make it illegal. However, an alternative approach would be to consider a renaming-as-body that appears before the subprogram is frozen as equivalent to a renaming-as-spec, and hence the above would be legal (since for renaming-as-spec, only the types and modes, not the subtypes, matter). In any case, I consider this a pathology, and would not welcome the creation of an ACVC test for it. > private > type T is new Natural; > -- alternatively, type T is new Float; > end > > function Foo2 (L, R : P.T) return Boolean; > function Foo2 (L, R : P.T) return Boolean renames "="; -- legal? > > Does he completion of type T affect the legality of the renaming-as-bodies in > these examples? I suspect current rules would indicate that it does. However, that violates the more general rule regarding "privacy" of private declarations, so, as suggested above, we might want to further relax the restrictions on "early" renaming-as-bodies, since we have already relaxed the rule on convention Intrinsic for them. > The language would be more useful if 'Base was allowed in a limited number of > circumstances for non-scalar types; in particular, it would be nice to be able > to write an Ada specification for the predefined operators. I don't agree, given the existing restrictions on "late" renaming-as-body applied to intrinsic-convention subprograms like the predefined operators, as given in 8.5.4(5). > Pascal Leroy +33.1.30.12.09.68 > pleroy@rational.com +33.1.30.12.09.66 FAX -Tuck From lehman@ida.org Thu Aug 22 12:13:16 1996 Return-Path: Received: from inmet.camb.inmet.com by dsd.camb.inmet.com (4.1/SMI-4.1) id AA11357; Thu, 22 Aug 96 12:13:16 EDT Received: from sw-eng.falls-church.va.us (ns1.sw-eng.falls-church.va.us) by inmet.camb.inmet.com (4.1/SMI-4.1) id AA28363; Thu, 22 Aug 96 12:13:30 EDT Received: from ida.org by sw-eng.falls-church.va.us (8.7.1/) id QAA18357; Thu, 22 Aug 1996 16:11:44 GMT Received: from poseidon.csed.ida.org by ida.org (4.1/SMI-4.1) id AA27641; Thu, 22 Aug 96 12:13:09 EDT Received: by poseidon.csed.ida.org (SMI-8.6/SMI-SVR4) id MAA07727; Thu, 22 Aug 1996 12:13:10 -0400 Date: Thu, 22 Aug 1996 12:13:10 -0400 From: lehman@ida.org (Dan Lehman) Message-Id: <199608221613.MAA07727@poseidon.csed.ida.org> To: Ada-Comment@sw-eng.falls-church.va.us Subject: Controversial visibility of inherited private components in a child unit Cc: 100071.47@CompuServe.COM X-Sun-Charset: US-ASCII !topic Controversial visibility of inherited private components in a child unit !reference RM95 7.3(15), 7.3.1(3), 7.3.1(10), 8.2(4) !reference 96-5635.a Bernard Maudry 96-8-21 !from Dan Lehman 96-08-22 !keywords visibility inherited private components child <> !discussion I conclude that the example given by Bernard Maudry in raising this issue is legal, that both Name & Kind are visible components at the point where he reports some compilers (names, please?) reporting an illegality (it would be nice to know what those compilers report!). Am I missing something? I'll re-cast his example, as the original msg. *disformatted* it (NB: I'VE CHANGED THE INSTANCE NAME FROM "EXTRA" TO "LOWER", which I think will avoid adding confusion re the generic unit "Extra"): package Top is type Node is abstract tagged private ; private type Node is abstract tagged record Name : Integer := 0; end record; end Top ; package Top.Mid is type Node is abstract new Top.Node with private ; private type Node is abstract new Top.Node with record Kind : Integer := 0; end record; end Top.Mid ; with Top.Mid; generic type Parent is abstract new Top.Mid.Node with private; package Top.Extra is type Node is abstract new Parent with null record ; end Top.Extra ; with Top.Mid; with Top.Extra; package Top.Mid.LOWER is new Top.Extra (Parent => Top.Mid.Node); with Top.Mid.LOWER ; package Top.Mid.Bot is type Node is new Top.Mid.LOWER.Node with null record ; The_Node : Node ; private -- The legality of the two following lines of code is controversial. -- Of 4 Ada95 compilers, 2 of them think they are legal, -- and the 2 others reject them as illegal. -- Where is the truth ? Why ? Buggy_1 : Integer := The_Node.Name; -- LEGAL ?? (yes) Buggy_2 : Integer := The_Node.Kind; -- LEGAL ?? (yes) end Top.Mid.Bot ; I conclude that the controversial lines are legal. Were "private" removed from Top.Mid.Bot, then they'd be illegal as per 8.2(4). ---Dan Lehman -------------- * ============================================================================= From stt@dsd.camb.inmet.com Thu Aug 22 14:29:27 1996 Return-Path: Received: from inmet.camb.inmet.com by dsd.camb.inmet.com (4.1/SMI-4.1) id AA12201; Thu, 22 Aug 96 14:29:27 EDT Received: from sw-eng.falls-church.va.us (ns1.sw-eng.falls-church.va.us) by inmet.camb.inmet.com (4.1/SMI-4.1) id AA00533; Thu, 22 Aug 96 14:29:41 EDT Received: from dsd.camb.inmet.com by sw-eng.falls-church.va.us (8.7.1/) id SAA21471; Thu, 22 Aug 1996 18:27:54 GMT Received: from henning.camb.inmet.com.i2ada by dsd.camb.inmet.com (4.1/SMI-4.1) id AA12198; Thu, 22 Aug 96 14:28:52 EDT Date: Thu, 22 Aug 96 14:28:52 EDT From: stt@dsd.camb.inmet.com (Tucker Taft) Message-Id: <9608221828.AA12198@dsd.camb.inmet.com> To: ada-comment@sw-eng.falls-church.va.us Subject: Class-wide types as generic actuals !topic T'Class as generic actual type !reference RM95-12.5(6) !reference RM95-12.5.1(17,21) !from Tucker Taft 96-08-22 <> !discussion Although it is not explicitly stated, a class-wide type may be passed as a generic actual type, so long as the formal is indefinite, and either private, or a private extension of some ancestor of the root of the class-wide type. Inside the generic, you get a set of primitive operations determined by the formal type declaration, which in the case of a nonlimited private, consists of "=" and "/=", and for a formal private extension, a full set of user-defined primitive operations. The question is -- what happens if we rename one of these implicitly declared ops? For example: package Pkg is type Root is tagged ... procedure P(R : Root); function Empty return Root; end Pkg; with Pkg; generic type T(<>) is new Pkg.Root with private; -- primitives are implicitly declared here: -- function "="(Left, Right : T) return Boolean; -- procedure P(R : T); -- function Empty return T; package Gen is -- Now what happens if we rename these ops? procedure My_P(R : T) renames P; function Equals(L, R : T) return Boolean renames "="; function My_Empty return T renames Empty; end Gen; with Pkg, Gen; package Inst is new Gen(Pkg.Root'Class); -- What exactly are the semantics of Inst.My_P, -- Inst.Equals, and Inst.My_Empty? -- Are all calls on them dispatching? -- Hmmmm.... Now this is not just an idle exercise, though it may seem so at first. Another thing you might want to do is: generic type T(<>) is tagged private; with function Empty return T is <>; package Another_Gen is ... Ideally the following instantiation would be legal: with Pkg, Another_Gen; package Another_Inst is new Another_Gen(Pkg.Root'Class); If this were to be legal, what "Empty" are we implicitly passing as a generic actual? During the 9X design process, Norm Cohen (NC1 ;-) (and others) periodically recommended that we "reify" the dispatching operations, by claiming that there are implicit declarations of operations on T'Class which automatically dispatch when you call them. We had originally had a model like this, but it grew overly complex, and seemed to introduce nasty ambiguities between the operations on T'Class and T. However, when you start instantiating a generic with T'Class, these operations seem to somehow magically reappear in the model. Furthermore, it would be very nice if an instantiation like Another_Inst would work, as this would provide a crucial piece in constructing a flexible Java "interface type"-like notion of a type implementing multiple generic "signatures". Hence, without further ado, I suggest the following *model* for defining the semantics of dispatching calls, as well as what you get when you instantiate a generic with a class-wide actual... IMPLICIT DECLARATION MODEL FOR DISPATCHING CALLS When a primitive operation is declared on a tagged type, a corresponding "dispatching-only" operation is declared on a type we will herein dub T'Class_Only, which is somewhat like T'Class, except that it only allows actual parameters of types T'Class and T'Class_Only, and is *not* implicitly convertible to T'Class (to avoid ambiguities). For example, going back to the "Pkg" above, we get the following: package Pkg is type Root is tagged ... procedure P(R : Root); function Empty return Root; -- The following implicit declarations occur: -- First the usual =, /= : -- function "="(Left, Right : Root) return Boolean; -- function "/="(Left, Right : Root) return Boolean; -- Now for the "dispatching-only" operations -- (these are all convention Intrinsic) -- function "="(Left, Right : Root'Class_Only) return Boolean; -- function "/="(Left, Right : Root'Class_Only) return Boolean; -- procedure P(R : Root'Class_Only); -- function Empty return Root'Class_Only; end Pkg; These Root'Class_Only operations are effectively the "primitive" operations of the type Root'Class. Root'Class_Only can be thought of as a subtype of Root'Class, but which lacks the implicit convertibility associated with Root'Class. Note that once we introduce these 'Class_Only operations, we can eliminate all the funny business about statically and dynamically tagged expressions, tag-indeterminate expressions, and the funny rule which allows T'Class to be passed when T is expected, but only as part of a dispatching call. All of these rules are subsumed by the normal overload resolution rules, where T'Class_Only is treated as a separate type which is *not* covered by T'Class, and covers only T'Class and T'Class_Only. The notion of a dynamically tagged expression reduces to simply something of type T'Class or T'Class-Only. The rules for dispatching assignment statements are also subsumed by simply presuming the existence of a T'Class_Only assignment operation. The special rule for class-wide "=" can also be explained by saying that the implicitly declared 'Class_Only "=" returns False if the tags don't match. There is no need for any mention of the explicit use of the "=" operator in the call, since it only the 'Class_Only "=" that has this property. The rule that renaming does not automatically "carry" over dispatching-ness also works naturally, since a rename is renaming the T, not the T'Class_Only operation. Finally, getting back to generic instantiation. It is the 'Class_Only operations that "come along" with an actual class-wide type in an instantiation. Given that, there then becomes no particular reason that such operations should not match explicit formal subprograms, like the "Empty" one in Another_Gen above. This leads to the general notion that T'Class_Only matches T'Class for the purposes of generic formal/actual subprogram matching, and presumably also subprogram renaming-as-spec. That is, T'Class_Only and T'Class are "type conformant" but not "subtype conformant". Note that on a subprogram renaming-as-spec, the original parameter subtypes "show through" the renaming, and so a renaming of an implicitly declared dispatching operation, as in: function My_Empty return Pkg.Root'Class renames Pkg.Empty; produces a function whose result subtype is still "Pkg.Root'Class_Only, and is hence a dispatching-only function. SUMMARY The above model simplifies the explanation of the semantics at one level, but introduces a bunch of implicit declarations at another level. Hence, one way to handle it is to use it simply as a model to derive the rules, without forcing all of the implicit declarations onto the users' conscience until they want them. In many ways, the above notion of a 'Class_Only type is analogous to the root_integer and root_real types. They make the underlying model cleaner, but most users don't want to think about them, and are willing to just live with the rules implied by the underlying model without having to understand the model itself. Hence, with that attitude, the net effect of the above proposal is that subprogram renaming and generic formal/actual subprogram matching is somewhat relaxed, to allow a dispatching operation to be renamed/matched by a subprogram that has T'Class instead of T at each of the controlling parameter/result places. What is produced is a subprogram that dispatches when called with class-wide (or dynamically-tagged) operands, even though it isn't declared immediately within the immediate scope of the controlling type. USING NEW RULE TO IMPLEMENT MULTIPLE INTERFACES The thing which interested me in this from the beginning was trying to come up with a good fit for the Java notion of an "Interface" type. In Java, a class only has one parent (i.e. single inheritance), but may claim to "implement" any number of "interface" types. What that means is that the class must implement each of the methods specified in the interface type declaration. However, no code is inherited from the interface type, only the specs for the methods. So this might be called single inheritance of implementation, and multiple inheritance of interface. Ada's generics provide a very nice, and potentially more flexible way, of defining multiple interfaces to be implemented by a type. For example: generic type Set(<>) is private type Element(<>) is private; with function Union(L, R: Set) return Set is <>; with function Intersection(L, R: Set) return Set is <>; with function Empty return Set is <>; with function Unit_Set(E : Element) return Set is <>; with procedure Take(S : in out Set; E : out Element) is <>; package Set_Interface is end; We can take any set-like type, and create an instantiation of this "Set_Interface" generic, and then use it in other generics which have a formal package parameter that is an instance of Set_Instance. We can make this usable outside of generics by coupling it with access discriminants: with Window_Interface; package Pkg is -- First declare a type of some sort type My_Type is tagged limited ... ... -- Now show how it implements the "Window" interface, possibly -- with different operation names package Implements is new Window_Interface.Implements(My_Type'Class, Display => Draw, Resize => Specify_Size); -- Now we can create a type that can "behave" as a Window by -- adding a "surrogate" component of the type Implements.Window. type My_Type_With_Window is new My_Type with record Window : aliased Implements.Window(My_Type_With_Window'Access); ... -- other "Implements" components. end record; -- Given X of type My_Type_With_Window, X.Window can be -- passed any place where an object implementing the interface -- defined in Window_Interface is required. end Pkg; The above all relies on the use of My_Type'Class as a generic actual, and the ability of formal subprograms to match actual dispatching operations. Here is a possible implementation of the generic used above: package Window_Interface is type Window is abstract tagged limited private; procedure Display(this : access Window) is abstract; procedure Resize(this : access Window; Height, Width : Dimension) is abstract; ... generic type Implementor(<>) is tagged limited private with procedure Display(this : access Implementor) is <>; with procedure Resize(this : access Implementor; Height, Width : Dimension) is <>; ... package Implements is type Window(Encloser : access Implementor) is new Window_Interface.Window with null record; procedure Display(this : access Window); procedure Resize(this : access Window; Height, Width : Dimension); ... end Implements; end Window_Interface; package body Window_Interface; package body Implements is procedure Display(this : access Window) is begin -- This dispatches if Implementor is a class-wide type. Display(this.Encloser); end; procedure Resize(this : access Window; Height, Width : Dimension) is begin -- This dispatches if Implementor is a class-wide type. Resize(this.Encloser, Height, Width); end; ... end Implements; end Window_Interface; Note how this approach takes advantage of the flexibilty in generic formal/actual subprogram parameter matching; it allows a type to implement an interface without having exactly matching names for operations. Although creating the generic is a bit tedious, using it, as illustrated above, is fairly clean. That's all for now! -Tuck