1

I am trying to create a package that has Dynamic dispatching using access types. I have achieved Dynamic Dispatching using Class Types using This Q/A as a guide.

I keep getting a compilation error that says: cannot call abstract subprogram. This makes me think that the compiler either doesnt recognize the specialized subprogram, or doesnt recognize the type as a specialized type. But both seem right to me... I dont get it.

main.2.ada

with Ada.Text_IO;
with Animal.Cat;

procedure Main is
    Tabby        : aliased Animal.Cat.Cat_t;
    Animal_Ref   : Animal.Any_Animal_Ptr := Tabby'Unchecked_Access;
    Result       : Boolean;
begin
    Animal.Stroke_Fur (Animal => Animal_Ref.all);

    Result := Animal.Is_Happy(Ptr => Animal_Ref);

    Ada.Text_IO.Put_Line ("Happy Animal = " & Boolean'Image (Result));

end Main;

animal.1.ada

package Animal is

    type base_t is abstract tagged limited null record;

    type Animal_t is abstract new 
        base_t with private;

    type Any_Animal_Ptr is access all Animal_t'Class;
    ----
    procedure Stroke_Fur (Animal : in out Animal_t) is abstract;
    ----
    function Is_Happy (Ptr : in Any_Animal_Ptr) return boolean is abstract;

private

    type Animal_t is abstract new base_t with 
    record
        Index : integer;
    end record;

end Animal;

animal.cat.1.ada

package Animal.Cat is

    type Cat_t is new Animal.Animal_t with private;
    type Cat_Ptr is access all Cat_t;

    ----
    procedure Stroke_Fur (Cat : in out Cat_t);
    ----
    function Is_Happy (Ptr : in Cat_Ptr) return Boolean;

private
    type Cat_t is new Animal.Animal_t with 
    record
        Purr : Boolean := False;
    end record;            

end Animal.Cat;

animal.cat.2.ada

package body Animal.Cat is

    ----
    procedure Stroke_Fur (Cat : in out Cat_t) is
    begin
        Cat.Purr := True;
    end Stroke_Fur;
    ----
    function Is_Happy (Ptr : in Cat_Ptr) return Boolean is
    begin
        return Ptr.Purr;
    end Is_Happy;

end Animal.Cat;

Error

main.2.ada:13:21: cannot call abstract subprogram "Is_Happy"

Community
  • 1
  • 1
Jerunh
  • 524
  • 5
  • 16
  • 1
    Why are you using access types as well as dynamic dispatching? It might be easier, if you experimented only with dynamic dispatching. – Jacob Sparre Andersen Mar 10 '16 at 09:05
  • @JacobSparreAndersen - I am using access types because in my actual code, I am using fairly large objects, which is not a fact I can change. I would rather explicitly use pointers than hope for the optimizer to do so for me. I thought I used dynamic dispatching with my method `Stroke_Fur`, and it worked. Could you clarify why you asked this question? It sounds like you are inferring that the two should be mutually exclusive, but I'm not really certain what you mean. – Jerunh Mar 10 '16 at 14:03
  • Most Ada programmers have come to rely on their compiler vendors not to generate grossly inefficient code. The parameter modes indicate intention; with `access` you’re not quite sure what’s going to happen to the passed object. Tagged types are by-reference anyway ([AARM05 6.2](http://www.adaic.org/resources/add_content/standards/05aarm/html/AA-6-2.html)). – Simon Wright Mar 10 '16 at 22:07
  • @Jerunh I asked because using access types is an unneeded complication, which may hide your actual challenges with tagged types. (And as Simon writes, tagged types are pass-by-reference types, so the optimiser doesn't have any say in how they are passed as parameters.) – Jacob Sparre Andersen Mar 11 '16 at 09:56

1 Answers1

3
function Is_Happy (Ptr : in Any_Animal_Ptr) return boolean is abstract;

isn’t a primitive operation (ARM3.2.3(2)) of Animal_t, and so it isn’t dispatching; it’s merely an abstract subprogram (which therefore can’t be called).

Why would you want to make a non-dispatching subprogram abstract? Perhaps you might have a type Metres, in which case the predefined ”*” is inappropriate (multiplying two distances in metres returns an area, not a distance) and you might want to make it abstract to prevent inadvertent misuse.

Anyway, you can declare a primitive operation of Animal_t using accesses as

function Is_Happy (Ptr : access Animal_t) return boolean is abstract;

and then for cats

function Is_Happy (Ptr : access Cat_t) return Boolean;

(or even

overriding
function Is_Happy (Ptr : access Cat_t) return Boolean;

if you want the compiler to check that it really is overriding).

By the way, if you are using Ada 2005 or later you can use the prefixed notation to write the calls as

Animal_Ref.Stroke_Fur;
Result := Animal_Ref.Is_Happy;

which is prettier.

Simon Wright
  • 25,108
  • 2
  • 35
  • 62
  • Thank You. My method is abstract because it doesn't make sense to a default implementation. Obviously, this was just a simple example that I wrote to share. I believe most Ada programmers probably can't share their actual code for one of several reasons. Plus 9 times out of 10 when I create a simplified example to share, I usually solve my own problem. Thanks again, this was helpful and solved my problem. – Jerunh Mar 10 '16 at 13:54