ada

Compile error when implementing interface


I am experimenting a bit (out of academic interest, no tangible use-case) with protected interfaces and have come-up with the following code:

procedure Protected_Map is
   type Key is new Character range 'A' .. 'K';
   type Value is range -10 .. 10;
   
   package Maps is
      type Map is protected interface;
      procedure Insert(M: out Map; K: in Key; V: in Value) is abstract;
      procedure Find(M: in out Map; K: in Key; V: out Value) is abstract;
   end Maps;
   use Maps;
   
   -- protected type implementation
   protected type A_Map is new Map with
      overriding
      procedure Insert(K: in Key; V: in Value);
      not overriding
      function Get(K: in Key) return Value;       
   end A_Map;
   
   protected body A_Map is
      procedure Insert(K: in Key; V: in Value) is null; -- dummy
      function Get(K: in Key) return Value is (0); -- dummy
   end A_Map;
   
   overriding
   procedure Find(M: in out A_Map; K: in Key; V: out Value) is
   begin
      V:= M.Get(K);
   end Find;
begin
   null;
end Protected_Map;

The idea is to implement a task-safe Map by declaring a protected interface type with the associated procedures of inserting and finding values by some key. A protected type is then declared in order to implement the interface which only partly implements it (i.e. Insert(..)) and introduces a Get(..) function to retrieve a value by some key. The second required procedure (Find(..)) is implemented in an independent full-blown way. The reason for this is so that writers continue to access the map in a mutually exclusive way whilst readers are able to access it concurrently.

However, compilation is failing for Find(..) with the compiler complaining that no selector "Get" for type derived from A_Map. Why can it not see Get which is clearly in the protected type declaration? Is it a scoping issue i.e. do the protected type declaration and the independent implementation need to be in the same package? (or some other unit?)


Solution

  • The problem is your compiler has a bug with the error message. The actual error you are making is trying to declare an overriding operation of your A_Map type after specifying a body for the protected type. Ada wants you to declare all your overrides before the type "freezes" and making a body for the protected type freezes it. If you add in a declaration for your Find procedure before the body of the protected type, then all is good. It's a bad error message.

    See example

    with Ada.Text_IO; use Ada.Text_IO;
    
    procedure jdoodle is
        procedure Protected_Map is
           type Key is new Character range 'A' .. 'K';
           type Value is range -10 .. 10;
           
           package Maps is
              type Map is protected interface;
              procedure Insert(M: out Map; K: in Key; V: in Value) is abstract;
              procedure Find(M: in out Map; K: in Key; V: out Value) is abstract;
           end Maps;
           use Maps;
           
           -- protected type implementation
           protected type A_Map is new Map with
              overriding
              procedure Insert(K: in Key; V: in Value);
              not overriding
              function Get(K: in Key) return Value;       
           end A_Map;
           
           -- Notice the declaration I added here before the body code.
           overriding
           procedure Find(M: in out A_Map; K: in Key; V: out Value);
           
           protected body A_Map is
              procedure Insert(K: in Key; V: in Value) is null; -- dummy
              function Get(K: in Key) return Value is (0); -- dummy
           end A_Map;
           
           procedure Find(M: in out A_Map; K: in Key; V: out Value) is
           begin
              V:= M.Get(K);
           end Find;
        begin
           null;
        end Protected_Map;
    begin
        null;
    end jdoodle;
    

    at https://www.jdoodle.com/ia/K4h