In object-oriented programming, it is often the case that we want
to override a primitive operation from a parent type.
While some languages have built-in support for this (for instance
python has the super()
operation for that), it is not the case
with Ada.
In this post, we will be looking at the classical example of geometric
figures, starting with the parent type:
package Polygons is type Polygon is tagged private; procedure Prim (Self : in out Polygon); end Polygons;
The simplest approach is to convert your parameter to the parent type
explicitly and then call the function. For instance:
package Squares is type Square is new Polygons.Polygon with private; overriding procedure Prim (Self : in out Square); end Squares; package body Squares is overriding procedure Prim (Self : in out Square) is begin Prim (Polygons.Polygon (Self)); -- calling inherited ... end Prim; end Squares;
The risk here occurs when we later decide that a square really is a special
case of a rectangle, we might forget to update the call to Prim on the last
line above, to convert to Rectangle
instead of Polygon
.
In an earlier blog post at another company, we suggested one possible approach.
The idea is to always declare a Parent
subtype and use that when calling
the inherited subprogram:
package Squares is subtype Parent is Polygons.Polygon; type Square is new Parent with private; overriding procedure Prim (Self : in out Square); end Squares; package body Squares is overriding procedure Prim (Self : in out Square) is begin Prim (Parent (Self)); -- calling inherited ... end Prim; end Squares;
Now we only have to change the declaration of Parent
to implement squares
as a special case of rectangles, and will automatically call the inherited
procedure from Parent
.
But in fact, there exists yet another approach which we find more elegant.
The idea is to rename the inherited procedure *before* we declare the
overriding procedure. For instance:
package Squares is type Square is new Parent with private; procedure Inherited_Prim (Self : in out Square) renames Prim; overriding procedure Prim (Self : in out Square); end Squares; package body Squares is overriding procedure Prim (Self : in out Square) is begin Inherited_Prim (Self); ... end Prim; end Squares;
This approach is better documenting when one reads the code.