Search code examples
oopgenericsmultiple-inheritanceada

Multiple type inheritance in ADA via generic mixins


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):

class hierarchy

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.


Solution

  • 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.)