โŒ About FreshRSS

Normal view

There are new articles available, click to refresh the page.
Before yesterdayNews from the Ada programming language world

Difference between statements inside and outside accept block

Suppose the following (server) task specification:

task type Server_Task is
      entry E1(I: Integer);
      entry E2;
      entry E3;
end Server_Task;

with a (dummy) implementation of:

task body Server_Task is      
   begin
      loop
         select
            accept E1(I: Integer) do
               -- statements inside E1 using I
               -- statements inside E1 using I
               -- statements inside E1 using I
               null;
            end;                       
         or
            accept E2 do
               null;               
            end;
         or
            accept E3 do
               null;
            end; 
         end select;         
      end loop;     
end Server_Task;

Based on my understanding, if a client task makes an entry call for (say) E1 then all statements inside the E1 accept block will be executed before the server task loops over again and is ready to accept another entry call. The same is true if there are further statements following the end of the accept block so that again all these will need to run before the task can randevouz with a calling task again. If that assumption is correct, I'm wondering what the behavioural difference is between the above implementation and the one below:

task body Server_Task is
      Temp: Integer;
   begin
      loop
         select
            accept E1(I: Integer) do
               Temp := I;       
            end;
            -- statements outside E1 using Temp
            -- statements outside E1 using Temp
            -- statements outside E1 using Temp
         or
            accept E2 do
               null;               
            end;
         or
            accept E3 do
               null;
            end; 
         end select;         
      end loop;     
end Server_Task;

Will there be a difference if the statements outside E1 make a blocking call and hence the server task is suspended and therefore these statements will then have to somehow compete with any other entry calls made by the task's clients? (though this doesn't make much sense if the task is implemented using just one "thread"?)

For the sake of argument suppose the client code is along the lines of:

ST: Server_Task;   
   task body Client_Task is
   begin
      select
         ST.E2;
      else
         -- do something else
         null;
      end select;
      null;
   end Client_Task;

Is this behaviour detailed somewhere in the ARM? - Thanks

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

Penultimate array index retrieval

Suppose the following generic procedure to print the elements of an array indexed by a discreet type (note the slight logic added to prevent the printing of an extra , past the end of the last element):

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Array_Printer is
   
   generic
      type Index is (<>);
      type Int_Array is array (Index range <>) of Integer;
   procedure Print(IA: Int_Array); 
   
   procedure Print(IA: Int_Array) is
      -- Penultimate: Index := Index'Pred(IA'Last); -- raises CONSTRAINT_ERROR for IA'Length = 1
   begin
      Put("[");
      for I in IA'First .. Index'Pred(IA'Last) loop
         Put(IA(I), 0);Put(",");
      end loop;
      Put(IA(IA'Last), 0);
      Put("]");      
   end Print;
   
   type Int_Array is array(Positive range <>) of Integer;
   
   IA: Int_Array := (-3, -2, -1, 0, 1, 2, 3);
   IA2: Int_Array := (1 => 0);
   
   procedure Print_Int_Array is new Print(Index => Positive,
                                          Int_Array => Int_Array);
   
   begin
      Print_Int_Array(IA);   
end Array_Printer;

When this procedure runs with an array of length > 1 (e.g. IA) it correctly prints the array ([-3,-2,-1,0,1,2,3]). However, when it is given an array of length = 1 (e.g. IA2) then, perhaps surprisingly, the penultimate index calculation in the for-loop doesn't raise a CONSTRAINT_ERROR (due to a predecessor not existing) and the expected result ([0]) gets printed.

When that calculation is done elsewhere however (e.g. in the declarative section of the procedure) then that exception is raised, indeed.

Is the compiler smart enough to figure-out there's only one element in the array and hence generates a null range for the for loop?

Gnatstudio seems to be invoking gprbuild with -cargs -g -O0

Any thoughts? - Thanks

โŒ
โŒ