comp.lang.ada
 help / color / mirror / Atom feed
* Newbie-ish question about generics and Ada.Streams
@ 2010-12-27 17:23 Brian Drummond
  2010-12-27 18:59 ` Robert A Duff
  0 siblings, 1 reply; 3+ messages in thread
From: Brian Drummond @ 2010-12-27 17:23 UTC (permalink / raw)


Season's greetings!

In between rounds of turkey, I have been trying to learn a bit more about generics, though it still
feels as if I am pushing on a rope.

In particular, I have been trying to use generic procedures for stream access for a large set of
similar data types (enumerations) where I want a specific representation in the output file. This
means attaching the Read and Write procedures - instantiated generics - to the types using
representation clauses.

Which (as I understand it) has to be done before the types are frozen....

I hope the example below is clear...

Comments welcome, but the specific points I am unhappy with are:

(1) The incomplete procedure declarations, with deferred implementation. 
I suspect there is no way around this, as long as I need to freeze the type 
before the procedure body.

(2) The second generic parameter - the named array type. It feels like I am missing 
something obvious here, and there ought to be a way to avoid adding this clutter.

(3) Instantiating the generic under a different name, and renaming to match the incomplete
declaration. Is this (a) necessary, (b) Gnat-specific, or (c) something stupid on my part?

Thanks,
- Brian


with Ada.Text_Io.Text_Streams;
with Ada.Streams;

procedure try_generics is

-- We have multiple enumerations...
type shape is (circle, square);
type colour is (red, green, blue);

-- and we want to control how they are written to a stream
procedure colour_write (Stream : not null access Ada.Streams.Root_Stream_Type'Class; 
			what : in colour);
procedure shape_write (Stream : not null access Ada.Streams.Root_Stream_Type'Class; 
			what : in shape);
for colour'write use colour_write;
for shape'write use shape_write;

-- In this example, we use an array of strings indexed by the enumerations.
-- shapes : constant array(shape) of string(1 .. 7) := ("circle ", "square ");
-- but... generics (below) seem picky about using named vs anonymous subtypes
subtype name is string(1 .. 7);
type shape_names is array(shape) of name;
type colour_names is array(colour) of name;
-- appears to freeze the types; write procedures or representation clauses after this are "too late"
shapes : constant shape_names := ("circle ", "square ");
colours : constant colour_names := ("red    ", "green  ", "blue   ");

-- Example body of a write procedure...
--procedure colour_write (Stream : not null access Ada.Streams.Root_Stream_Type'Class; 
			what : in colour) is
--begin
--   String'write(Stream, colours(what));
--end colour_write;

-- That would get repetitive, so let's use a generic...
   generic
      type Item_Type is (<>);
      type Item_Names(<>) is array(Item_Type) of name;
      -- Feels as if the Item_Names type declaration ought to be unnecessary...
      Names : Item_Names;
   procedure Enum_Write(Stream : not null access Ada.Streams.Root_Stream_Type'Class; 
			Item : in Item_Type);

   procedure Enum_Write(Stream : not null access Ada.Streams.Root_Stream_Type'Class; 
			Item : in Item_Type) is
   begin
      String'Write(Stream, Names(Item));
   end Enum_Write;

-- And instantiate it. First attempt...
--procedure shape_write is new Enum_Write(Item_Type => shape, 
			Item_Names => shape_names, Names => shapes);
--try_generics.adb:12:01: missing body for "shape_write"
--try_generics.adb:43:11: instantiation cannot provide body for "shape_write"

-- So instantiate it under a different name, and rename it...
procedure shape_writer is new Enum_Write(Item_Type => shape, 
			Item_Names => shape_names, Names => shapes);
procedure shape_write(Stream : not null access Ada.Streams.Root_Stream_Type'Class; 
			what : in shape) renames shape_writer;
procedure colour_writer is new Enum_Write(Item_Type => colour, 
			Item_Names => colour_names, Names =>colours);
procedure colour_write (Stream : not null access Ada.Streams.Root_Stream_Type'Class; 
			what : in colour) renames colour_writer;
-- That duplication is ugly ... can this be simplified?

-- Now we can use the enumerations in a toy block
type toy_block is record
   my_colour : colour;
   my_shape : shape;
end record;

-- and output the block to a stream
my_block : constant toy_block := (my_colour => red, my_shape => square);
Stdout : Ada.Text_Io.Text_Streams.Stream_Access :=
Ada.Text_Io.Text_Streams.Stream(Ada.Text_Io.Current_Output);
begin
   toy_block'write(Stdout, my_block); 
end try_generics;





^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Newbie-ish question about generics and Ada.Streams
  2010-12-27 17:23 Newbie-ish question about generics and Ada.Streams Brian Drummond
@ 2010-12-27 18:59 ` Robert A Duff
  2010-12-27 23:26   ` Brian Drummond
  0 siblings, 1 reply; 3+ messages in thread
From: Robert A Duff @ 2010-12-27 18:59 UTC (permalink / raw)


Brian Drummond <brian_drummond@btconnect.com> writes:

> Comments welcome, but the specific points I am unhappy with are:
> ...[3 things]

It's reasonable to be unhappy about these things.
There are no better workarounds than the ones
you have already discovered.

But why don't you use Shape'Image, possibly with
a call to To_Lower?

Or, in your tables mapping enums to strings, use
pointers, so you can make the strings exactly
the right length, instead of blank padding them?
Most likely, your enums will be in a library package
spec, so there's no need to Unchecked_Deallocate
the strings.

- Bob



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Newbie-ish question about generics and Ada.Streams
  2010-12-27 18:59 ` Robert A Duff
@ 2010-12-27 23:26   ` Brian Drummond
  0 siblings, 0 replies; 3+ messages in thread
From: Brian Drummond @ 2010-12-27 23:26 UTC (permalink / raw)


On Mon, 27 Dec 2010 13:59:27 -0500, Robert A Duff <bobduff@shell01.TheWorld.com>
wrote:

>Brian Drummond <brian_drummond@btconnect.com> writes:
>
>> Comments welcome, but the specific points I am unhappy with are:
>> ...[3 things]
>
>It's reasonable to be unhappy about these things.
>There are no better workarounds than the ones
>you have already discovered.

Thanks.

>But why don't you use Shape'Image, possibly with
>a call to To_Lower?

Because that would restrict the output to file, which I wanted to control. 
(It could be an actual toy block, if the target was Lego Mindstorms!)

It would certainly work for this example though - ditto the string pointers.
This was only intended as a simple example to illustrate the issue.

The real case involves binary data, not text; and under some 
circumstances I must perform manipulations such as endian swaps. (Otherwise I
could simply use the appropriate representation for the enumeration, and allow
the default Integer'Write to take care of it.)

Thanks,

- Brian



^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2010-12-27 23:26 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-12-27 17:23 Newbie-ish question about generics and Ada.Streams Brian Drummond
2010-12-27 18:59 ` Robert A Duff
2010-12-27 23:26   ` Brian Drummond

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox