I'm implementing a visitor pattern and I have some elements that I could implement using generics, but the GNAT compiler complains with the generic type.
I have a solution using generic mix-ins but its less intuitive.
How can I solve it?
I provide the following minimal reproducibable example:
- visitors.ads
with ConcreteElements;
with Instantiation;
package Visitors is
type Visitor_t is interface;
procedure pVisit (this : in Visitor_t;
element : ConcreteElements.ConcreteElement_t) is abstract;
procedure pVisit (this : in Visitor_t;
element : Instantiation.GenericElement_t) is abstract;
end Visitors;
- elements.ads
limited with Visitors;
package Elements is
type Element_t is abstract tagged null record;
procedure pAccept
(this : in Element_t;
visitor : in Visitors.Visitor_t'Class) is abstract;
end Elements;
- concreteelements.ads/adb
limited with Visitors;
with Elements;
package ConcreteElements is
type ConcreteElement_t is new Elements.Element_t with null record;
overriding
procedure pAccept
(this : in ConcreteElement_t;
visitor : in Visitors.Visitor_t'Class);
end ConcreteElements;
with Visitors;
package body ConcreteElements is
procedure pAccept
(this : in ConcreteElement_t;
visitor : in Visitors.Visitor_t'Class) is
begin
visitor.pVisit(this);
end pAccept;
end ConcreteElements;
- genericelements.ads/adb
with Elements;
limited with Visitors;
generic
type Parent_t (<>) is abstract new Elements.Element_t with private;
package GenericElements is
type GenericElement_t is new Parent_t with null record;
overriding
procedure pAccept (this : in GenericElement_t;
visitor : in Visitors.Visitor_t'Class);
end GenericElements;
with Visitors;
package body GenericElements is
procedure pAccept (this : in GenericElement_t;
visitor : in Visitors.Visitor_t'Class) is
begin
visitor.pVisit(this);
end pAccept;
end GenericElements;
- instantiation.ads
with GenericElements;
with Elements;
package instantiation is new GenericElements
(Parent_t => Elements.Element_t);
The compiler complains in the body of 4), at line 9:
expected type "instantiation.GenericELement_t" defined at genericelements.ads:8
found type "GenericElements.GenericElement_t" defined at genericelements.ads:8
My solution is to perform a mix-in, making GenericElement_t abstract, thus this would be 1), 4) and 5):
1)
with ConcreteElements;
with Instantiation;
package Visitors is
type Visitor_t is interface;
procedure pVisit (this : in Visitor_t;
element : ConcreteElements.ConcreteElement_t) is abstract;
procedure pVisit (this : in Visitor_t;
element : Instantiation.Instantiation_t) is abstract;
end Visitors;
-
with Elements;
generic
type Parent_t (<>) is abstract new Elements.Element_t with private;
package GenericElements is
type GenericElement_t is abstract new Parent_t with null record;
end GenericElements;
-
private with GenericElements;
limited with Visitors;
with Elements;
package instantiation is
type Instantiation_t is new Elements.Element_t with private;
overriding
procedure pAccept (this : in Instantiation_t;
visitor : Visitors.Visitor_t'Class);
private
package instantiation_pck is new GenericElements
(Parent_t => Elements.Element_t);
type Instantiation_t is new instantiation_pck.GenericElement_t with null record;
end instantiation;
with Visitors;
package body instantiation is
procedure pAccept (this : in Instantiation_t;
visitor : Visitors.Visitor_t'Class) is
begin
visitor.pVisit(this);
end pAccept;
end instantiation;
Can I implement correctly the first option or I shall implement it using mix-ins?
Thank you in advance and sorry for the ammount of code.