0
votes

I'm currently learning Ada during a university course on real-time programming languages and have a question about generics.

I have a generic procedure csv_put

package PSU_Logging is

   type logged_signal_names_t is (
      t,
      U_V1,
      I_L1,
      U_C1,
      I_L2,
      U_C2,
      I_Load
   );

private
   ... Some types, tasks and subprogramms ...

   generic
      type Item_Type_t is private;
      procedure csv_put (File : in File_Type; Item : in Item_Type_t);

end PSU_Logging;

with the definition

package body PSU_Logging is

   procedure csv_put (File : in File_Type; Item : in Item_Type_t) is
   begin
      Put (File, Item_Type_t'Image (Item));
      Put (File, ", ");
   end csv_put;

   procedure csv_put_float is new csv_put (Item_Type_t => Float);
   procedure csv_put_duration is new csv_put (Item_Type_t => Duration);
   procedure csv_put_signal_name is new csv_put (Item_Type_t => logged_signal_names_t);

   ... Definition of other things ...

end PSU_Logging;

So far so good. Too bad that I get the following error during compilation

Compile
   [Ada]          psu_logging.adb
      psu_logging.adb:9:18: prefix of "image" attribute must be a scalar type or a scalar object name
gprbuild: *** compilation phase failed

Any ideas? I thought I could use the generic type within the generic procedure just like any other type. Since all of my instances use scalar types, I thought that should not be a problem.

Btw: What is your favourite Ada tutorial / reference? I like the Wikibooks page on Ada but it's not completed yet.

2
Related : stackoverflow.com/questions/13417337/… Ada doesn't seem to have a way of specifying "any scalar type" to a generic. "any DISCRETE type ... yes ... type Item_Type_t is (<>); but that leaves you on your own for fixed and float types. - user_1818839

2 Answers

6
votes

A possible workround (forgive my recapitalisation, it’s how my editor is set up): supply the Image as a generic parameter,

generic
   type Item_Type_T is private;
   with function Image (Item : Item_Type_T) return String;
procedure Csv_Put (File : in File_Type; Item : in Item_Type_T);

procedure Csv_Put (File : in File_Type; Item : in Item_Type_T) is
begin
   Put (File, Image (Item));
   Put (File, ", ");
end Csv_Put;

and instantiate using ’Image where available, your own otherwise:

procedure Csv_Put_Float is new Csv_Put (Item_Type_T => Float,
                                        Image => Float'Image);
2
votes

In addition to asking how to do this, which was answered above, you also seem to want to know why it works the way it does. The generic formal type

type Item_Type_T is private;

may be instantiated with any actual type that has assignment and "=". This covers a wide variety of types, not all of which are scalar. The generic must be legal for all possible actual types. Since 'Image isn't legal for some possible actual types, you can't use it for this type in the generic.