With the aim of reducing testing and repeating code I have discovered the multiple inheritance via generic mix-in but I don't know how is the best way to achieve that, as well as best practices.
Having the following class hierarchy example (done with diagrams.net):
This is the spec of the generic:
generic
type S is abstract tagged private;
package GenericChild is
type GenericChild_T is abstract new S with private;
procedure P_SetGenericAttribute (Self : in out GenericChild_T;
i : Integer);
function F_GetGenericAttribute (Self : GenericChild_T)
return Integer;
private
type GenericChild_T is abstract new S with
record
GenericAttribute : Integer;
end record;
end GenericChild;
For the generic instantiation in Child1:
with Root;
with GenericChild;
package Child1 is
type Child1_T is new Root.Root_T with private;
private
package Child1_G is new GenericChild (Root.Root_T);
type Child1_T is new Child1_G.GenericChild_T with null record;
end package Child1;
I can use the methods defined on the Root_T class without problems but, when I try to use the generic methods that is what I get:
no selector "P_SetGenericAttribute" for private type "Child1_T" ...
This is the main.adb where I have tested that:
with Child1;
procedure Main is
Instance : Child1.Child1_T;
begin
Instance.P_SetRootAttribute(1); --ok
Instance.P_SetGenericAttribute(1); --illegal
end main;
Why? Because I have encapsulated the generic package instantiation? In that case, how is the best way to solve it? Creating public methods in the child classes and calling the private generic instantiation methods within the method implementation? Because I would like to keep the generic instantiation as private. By doing this I'm able to set and get the attribute of the generic.
These are the changes performed to child1.ads that works for me:
with Root;
with GenericChild;
package Child1 is
type Child1_T is new Root.Root_T with private;
procedure P_SetGenericAttribute (Self : in out Child1_T;
i : Integer);
function F_GetGenericAttribute (Self : Child1_T)
return Integer;
private
package Child1_G is new GenericChild (Root.Root_T);
type Child1_T is new Child1_G.GenericChild_T with null record;
end package Child1;
And this is the child1.adb that completes it and works, but I'm not sure if it is a better way to achieve it, such as renaming or something else:
package body Child1 is
procedure P_SetGenericAttribute (Self : in out Child1_T;
i : Integer) is
begin
Child1_G.GenericChild_T(Self).P_SetGenericAttribute (i);
end P_SetGenericAttribute;
function F_GetGenericAttribute (Self : Child1_T)
return Integer is
i : Integer;
begin
i := Child1_G.GenericChild_T(Self).F_GetGenericAttribute;
return i;
end F_GetGenericAttribute;
end package Child1;
Any advice and/or best practices are welcome.
no selector "P_SetGenericAttribute" for private type "Child1_T" ...
The reason you're getting this error is because your implementation (the derivation of the instantiation of GenericChild) is private; your client simply cannot see that the type is such a derivation.
But you have a bigger problem: Ada does not do multiple inheritance like you diagram. You could do multiple interface
-types and derive from that, though. OR you could possibly use generic
and static polymorphism. -- But straight-up multiple inheritance won't work. (You can, as you mentioned, use mix-ins as well, but those aren't really inheritance.)