* 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