Reputation: 1807
I've got a parent package with some generic interface. I now want to create several implementations of this interface, each in a different file. I thought I could simply make these packages children to the package that contains the interface, instantiate the generic and then directly access the child packages, but this gives me an error that the child packages must be generic as well.
This lead me to the following implementation:
parent.ads:
generic
type T is private;
package Parent is
type I_Generic is interface;
type Any_Generic is access all I_Generic'Class;
function Get (This : in out I_Generic) return T is abstract;
procedure Set (This : in out I_Generic; Value : T) is abstract;
end Parent;
parent-child.ads:
generic
package Parent.Child is
-- long spec
type Impl is new I_Generic with private;
type Impl_Access is access all Impl;
overriding function Get (This : in out Impl) return T;
overriding procedure Set (This : in out Impl; Value : T);
private
type Impl is new I_Generic with
record
Data : T;
end record;
end Parent.Child;
parent-child.adb:
package body Parent.Child is
-- long body
overriding
function Get (This : in out Impl) return T is
begin
return This.Data;
end Get;
overriding
procedure Set (This : in out Impl; Value : T) is
begin
This.Data := Value;
end Set;
end Parent.Child;
tester.adb:
with Ada.Text_IO;
with Parent;
with Parent.Child;
package body Tester is
package Parent_Inst is new Parent (T => Integer);
package Child_Inst is new Parent_Inst.Child;
procedure Test is
Instance : constant Child_Inst.Impl_Access := new Child_Inst.Impl;
Polymorphic : constant Parent_Inst.Any_Generic := Parent_Inst.Any_Generic (Instance);
begin
Instance.Set (42);
Ada.Text_IO.Put_Line (Polymorphic.Get'Img);
end Test;
end Tester;
Result:
42
Why do I need to make the child package generic and then make an instance of it first? Why can't I simply use Instance : Parent_Inst.Child.Impl_Access := new Parent_Inst.Child.Impl;
?
Is there any way that I can do this cleaner? Perhaps I'm overlooking a different solution to my requirement that is simpler and doesn't have this problem? Or is this simply the way to achieve what I'm describing and should I just accept the verbosity of the extra package instantiation? In my own code I now have to make several package instantiations for each of the interface implementation packages, which results in many extra lines of code.
Upvotes: 5
Views: 476
Reputation: 39668
The child packages must be generic because of LRM 10.1.1, 17/3:
A child of a generic library package shall either be itself a generic unit or be a renaming of some other child of the same generic unit.
This is necessary because the child package can access the value of the generic parameter of the parent unit, which does not exist unless the parent unit is instantiated.
Now in Ada, generic instantiation is explicit and each instantiation instantiates exactly one generic unit. In your case,
package Parent_Inst is new Parent (T => Integer);
instantiates the Parent
package. It does not instantiate Parent.Child
because that is a separate generic unit. Therefore, you do need to instantiate Child
separately.
You can write a helper package that instantiates all at once, e.g.
generic
type T is private;
package Everything is
package Parent_Inst is new Parent (T);
package Child_Inst is new Parent_Inst.Child;
end Everything;
And then just instantiate Everything
where you need the instances.
Upvotes: 6