Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to access members of an Ada generic parameter

Tags:

ada

I am trying to write a generic package and one of the operations required is to checksum the data records received over a bus. The record type will vary and it is a generic parameter. However any attempts to access the members of the generic parameter cause a compilation error.

The error ... (Ada 95 GNAT 2009)

file.adb:XX no selector "Data" for private type "The_Transfer_Type" defined at file.ads:YY

The declaration...

generic
  type The_Transfer_Type is private;
  SIZE : Integer;
package CC_Test_Channel is
  function Checksum(Msg : The_Transfer_Type) return Integer;
end package

And the body ...

function Checksum(Msg : The_Transfer_Type) return Integer is
  Sum : Integer := 0;
begin
  -- calculate the checksum
  for i in 1 .. SIZE loop
    Sum := Sum + Integer(Msg.Data(i));
  end loop;
  return Sum;
end Checksum;
like image 579
mat_geek Avatar asked Feb 26 '10 01:02

mat_geek


2 Answers

When you specify that a generic parameter is a private type, well, Ada assumes you mean it :-)

I.e. you have no access to its components. Ada is not "duck typed", so it's irrelevant whether or not you know that an instantiating type might actually possess a particular field. (How would you expect your Checksum function to work if The_Transfer_Type parameter were instantiated with, say, Integer?)

One way to address this is to also supply an accessor function as a parameter to the generic that will retrieve the data needed to, in this case, compute the checksum. E.g.:

generic
   type The_Transfer_Type is private;
   with function Get_Checksummable_Data_Item
           (Msg : The_Transfer_Type;
            I   : Integer) return Integer;
   SIZE : Integer;

package CC_Test_Channel is
   function Checksum(Msg : The_Transfer_Type) return Integer;
end CC_Test_Channel;

The body is then:

function Checksum(Msg : The_Transfer_Type) return Integer is
   Sum : Integer := 0;
begin
   -- calculate the checksum
   for i in 1 .. SIZE loop
      Sum := Sum + Get_Checksummable_Data(Msg, I);
   end loop;
   return Sum;
end Checksum;

The function you supply for Get_Checksummable_Data is then specific to The_Transfer_Type and simply returns the selected value from The_Transfer_Type's component fields.

There are a number of other ways to set this up as well, like providing an unconstrained array type as a generic formal parameter and a formal function to retrieve it--this allows you to also get rid of the explicit SIZE formal parameter. Or you could write a Checksum() function as one of the operations on the type that you're instantiating CC_Test_Channel with, and then have:

with function Calculate_Checksum(Msg : The_Transfer_Type) return Integer;

as one of the generic formals.

Step back, and think about the possibilities...

like image 103
Marc C Avatar answered Oct 20 '22 00:10

Marc C


(moved from a comment, as this got long)

Ada (95 and later) supports streams. Unlike C++ streams, which are pretty much for string conversion, Ada streams are meant as a general mechanism for performing operations on data (typically I/O).

Every Ada object has 'Write and 'Read attributes. There are some language supplied streams (for file I/O), but you also have the ability to create your own by deriving from Ada.Streams.Root_Stream_Type. If you write your own stream in this way, there are some low-level routines that give you direct access to the data.

This allows you to write your own streams to perform operations like I/O, data compression, or in your case perhaps checksumming data from the bus before loading it into variables (via 'Read). I've done it myself in the past to implement a record/playback functionality for our real-time software. I looked into it for compression once too (we ended up not needing the compression).

like image 40
T.E.D. Avatar answered Oct 20 '22 00:10

T.E.D.