comp.lang.ada
 help / color / mirror / Atom feed
* Re: Ada.Streams examples
  1999-03-10  0:00 ` dennison
@ 1999-03-10  0:00   ` Rex Reges
  1999-03-10  0:00     ` dennison
  1999-03-10  0:00   ` Tom Moran
  1 sibling, 1 reply; 16+ messages in thread
From: Rex Reges @ 1999-03-10  0:00 UTC (permalink / raw)


dennison@telepath.com wrote:

> In article <36e61db4.50430543@news.pacbell.net>,
>   tmoran@bix.com (Tom Moran) wrote:
> > Could someone please point me to a text or tutorial or something on
> > using Ada.Streams - in particular overriding the default 'Read etc.
> >
>
> Cohen's latest edition of Ada as a Second Language goes over it.
>
> Basicly, you just declare a read routine with the following spec:
>
>    procedure Read
>      (Stream : access Ada.Streams.Root_Stream_Type'Class;
>       Item   : out    Instance
>      );
>
> where "Instance" is your type, in the same package spec that the type
> ("Instance in the above case) is declared. Then, after the full declaration
> of the type you put the following line:
>
>    for Instance'Read use Read;
>
> For the body of Read, you can call the 'Read method for the relevant field
> types yourself.
>
> Another option is to read in a properly sized Ada.Streams.Stream_Element_Array
> using the stream's Read method then use Unchecked_Conversion to convert the
> array type(s) you need. For instance:
>
>    Bytes_Per_Element  : constant := (Ada.Streams.Stream_Element'Size + 7) / 8;
>    Bytes_Per_Instance : constant Natural := (Instance'Size + 7) / 8;
>
>    Elements_Per_Header : constant Ada.Streams.Stream_Element_Offset :=
>      Ada.Streams.Stream_Element_Offset(
>        (Bytes_Per_Instance + (Bytes_Per_Element - 1)) / Bytes_Per_Element);
>    subtype Header_Array is Ada.Streams.Stream_Element_Array (1 ..
> Elements_Per_Header);
>
>    function To_Instance is new Unchecked_Conversion
>      (Source => Header_Array,
>       Target => Instance);
>
>    procedure Read
>      (Stream : access Ada.Streams.Root_Stream_Type'Class;
>       Item   : out    Instance
>      ) is
>
>       Trash : Ada.Streams.Stream_Element_Offset;
>       Item_Elements : Header_Array;
>    begin
>
>       Ada.Streams.Read
>         (Stream => Stream.all,
>          Item   => Item_Elements,
>          Last   => Trash
>          );
>
>       Item := To_Instance (Item_Elements);
>
>    end Read;
>
> A wise developer would probably check "Trash". But in my case I happen to
> know (because I wrote them) that the streams used for this call will raise
> exceptions rather than return a different Last than Item_Elements'Last.
>
> If there's anything else you are curious about, just ask.
>
> T.E.D.

Stream_IO solved the File IO difficulties that were in Ada 83. In Ada 83, the
elements put into a file were of some discriminated record.  This made it
necessary to have a huge structure to define all the possible things that one
might want to put in the file.  Stream_IO allows one to stuff any number of items
of varying type into a file as long as the user keeps track of this information
when the file is to be read again.

I would like to use Streams to create a similar package to Stream_IO, but write
to a memory object. If I have a "storage container", how can I fill it with
objects of varying types? How would I use Streams to do this?

Say I have container defined as follows:

  subtype Storage_Container is Streams.Stream_Element_Array ;

  type Medium_Storage_Container is Storage_Container( 0..511) ;


I'ld like to be able to code something like this:

   Parcel        : Medium_Storage_Container ;
   Parcel_Access : Container_Access         ;

   Parcel_Access := Start_Packing( Container => Parcel );

   String'Write ( Parcel_Access, "Dear Sir, The items you ordered." );
   Integer'Write( Parcel_Access,  2  );
   Gadget'Write ( Parcel_Access,  New_Gadget );
   Widget'Write ( Parcel_Access,  New_Widget );

   Stop_Packing( Container => Parcel );

The final step is to hand this Parcel off to a delivery service for shipping. The
delivery service doesn't care what's in the parcel, only what the size and
destination are.

I'm sure it must be easy to code this using Streams, but even with the ARM and
the Barnes book, I don't have a clear picture of what I need to do.


Rex Reges







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

* Re: Ada.Streams examples
  1999-03-10  0:00   ` Rex Reges
@ 1999-03-10  0:00     ` dennison
       [not found]       ` <36E7036B.EADEEA80@Boeing.com>
  0 siblings, 1 reply; 16+ messages in thread
From: dennison @ 1999-03-10  0:00 UTC (permalink / raw)


In article <36E6C291.F97766CB@Boeing.com>,
  Rex Reges <Rex.R.Reges@Boeing.com> wrote:

> I would like to use Streams to create a similar package to Stream_IO, but
write
> to a memory object. If I have a "storage container", how can I fill it with
> objects of varying types? How would I use Streams to do this?
>

I can probably give some advice here, as I have just written code to do that.
But first, I'll need requirements clarification. IAW: How do you want to use
it?

Does it need to support concurrent 'Writes from multiple tasks? Does it need
to support concurrent 'Writes with 'Reads?

Should it act just like a file, where written items start at the first
element and continue filling up the available space until it is exhausted? Or
should it act like a circular buffer where 'Read's will free up space that
may be used for later 'Writes?


T.E.D.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own    




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

* Re: Ada.Streams examples
  1999-03-10  0:00   ` Tom Moran
@ 1999-03-10  0:00     ` dennison
  1999-03-10  0:00       ` Tom Moran
  1999-03-11  0:00     ` Richard D Riehle
  1 sibling, 1 reply; 16+ messages in thread
From: dennison @ 1999-03-10  0:00 UTC (permalink / raw)


In article <36e6cd2c.3377267@news.pacbell.net>,
  tmoran@bix.com (Tom Moran) wrote:
>   I'll take a look at Cohen (my son took my copy away to college).

Cool! You must be very proud of him. :-)

>   I want to do an S'Read routine for a large array.  I really don't
> want to iteratively call Element'Read for each element.  Is there an
> alternative to the usual Unchecked_Conversion, overlaying, etc to get
> the data into my array?  If the array were in a Sequential_IO file I

Not that I've discovered. But in this context I don't see anything wrong with
Unchecked_Conversion. Converting types is what its there for.

>   The RM implies that an object's stream representation should be
> similar to its in-memory representation (a generalization from
> 13.13.2(17)).  If I have an object which has a standard external

Not only is that just implementation advice, but it also starts with the word
"If".

> representation (a Windows bmp bitmap, for instance) but a slightly
> different Ada representation in my program (discriminants, say), is it
> better to convert the object on Write to the "standard" external form,
> or to write it out as an Ada object as close as possible to its
> internal, Ada, memory form?  This is not addressed in AQS - anybody
> have any experience with these choices?

It depends on what you want to do. If you want to be able to write a bmp to
any stream, not just a file, then you should probably put the conversion in
the 'Write. If you will always write bmp's to the same type of stream, and
never want to put other non-bmp information in those same stream objects,
then it might make sense to create your own "bmp stream". If neither really
holds, I'd go with the one that seems the better abstraction in your
environment.

Now lets say you have a screen bitmap stored memory. You want to write this to
disk as a BMP file. I see three options:

  o  Create a 'Write procedure for that bitmap type which converts the bitmap
to a bmp and does one massive Write call for the stream. The problem with
this approach is that if anyone ever wants to do a 'Write on a bitmap for any
reason, the'll get a BMP. You can't overload it to get a JPG or GIF or a
straight memory dump (which is what they might be expecting).

  o  Create a new stream that converts Write data into GIF format, and saves
it to a file. The problem here is that the input data *must* be a bitmap of
our specified format, or this stream will produce garbage. There's no real
way in the language to enforce this. Also, we can't count on getting all the
data in one big Write call. This may be OK for BMP, but for a compressing
scheme like GIF it complicates matters.

  o  Create a Write_BMP and Read_BMP routine that take in files and bitmaps as
parameters, and forget about streams. Random objects cannot now be placed an a
"BMP" file.

The strength of streams IMHO is the ability to do I/O on hetrogenious data.
In our example I don't think that's a loss, so the last option is probably
the way to go.

T.E.D.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own    




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

* Re: Ada.Streams examples
  1999-03-10  0:00     ` dennison
@ 1999-03-10  0:00       ` Tom Moran
  1999-03-11  0:00         ` dennison
  0 siblings, 1 reply; 16+ messages in thread
From: Tom Moran @ 1999-03-10  0:00 UTC (permalink / raw)


>  o  Create a 'Write procedure for that bitmap type which converts the bitmap
>to a bmp and does one massive Write call for the stream. The problem with
>this approach is that if anyone ever wants to do a 'Write on a bitmap for any
>reason, the'll get a BMP. You can't overload it to get a JPG or GIF or a
>straight memory dump (which is what they might be expecting).
  Someone could presumably do
     type GIFED_Bitmap is new BMP with null record;
     for GIFED_Bitmap'Write use  Convert_To_GIF_And_Write;
Then internally a GIFED_Bitmap is the same as my BMP, and my routines
all work on it, but when the user writes it he gets his
Convert_To_GIF_And_Write instead of my BMP'Write.
No?
>  o  Create a Write_BMP and Read_BMP routine that take in files and bitmaps as
>parameters, and forget about streams.
  But with the BMP'Write I separate the file from the conversion, so
the result of the conversion could be handed to a called C routine,
say.  That seems to me a pretty strong argument for BMP'Write instead
of BMP_Write.




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

* Ada.Streams examples
@ 1999-03-10  0:00 Tom Moran
  1999-03-10  0:00 ` Steve Quinlan
  1999-03-10  0:00 ` dennison
  0 siblings, 2 replies; 16+ messages in thread
From: Tom Moran @ 1999-03-10  0:00 UTC (permalink / raw)


Could someone please point me to a text or tutorial or something on
using Ada.Streams - in particular overriding the default 'Read etc.




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

* Re: Ada.Streams examples
  1999-03-10  0:00 Ada.Streams examples Tom Moran
  1999-03-10  0:00 ` Steve Quinlan
@ 1999-03-10  0:00 ` dennison
  1999-03-10  0:00   ` Rex Reges
  1999-03-10  0:00   ` Tom Moran
  1 sibling, 2 replies; 16+ messages in thread
From: dennison @ 1999-03-10  0:00 UTC (permalink / raw)


In article <36e61db4.50430543@news.pacbell.net>,
  tmoran@bix.com (Tom Moran) wrote:
> Could someone please point me to a text or tutorial or something on
> using Ada.Streams - in particular overriding the default 'Read etc.
>

Cohen's latest edition of Ada as a Second Language goes over it.

Basicly, you just declare a read routine with the following spec:

   procedure Read
     (Stream : access Ada.Streams.Root_Stream_Type'Class;
      Item   : out    Instance
     );

where "Instance" is your type, in the same package spec that the type
("Instance in the above case) is declared. Then, after the full declaration
of the type you put the following line:

   for Instance'Read use Read;


For the body of Read, you can call the 'Read method for the relevant field
types yourself.

Another option is to read in a properly sized Ada.Streams.Stream_Element_Array
using the stream's Read method then use Unchecked_Conversion to convert the
array type(s) you need. For instance:

   Bytes_Per_Element  : constant := (Ada.Streams.Stream_Element'Size + 7) / 8;
   Bytes_Per_Instance : constant Natural := (Instance'Size + 7) / 8;

   Elements_Per_Header : constant Ada.Streams.Stream_Element_Offset :=
     Ada.Streams.Stream_Element_Offset(
       (Bytes_Per_Instance + (Bytes_Per_Element - 1)) / Bytes_Per_Element);
   subtype Header_Array is Ada.Streams.Stream_Element_Array (1 ..
Elements_Per_Header);

   function To_Instance is new Unchecked_Conversion
     (Source => Header_Array,
      Target => Instance);

   procedure Read
     (Stream : access Ada.Streams.Root_Stream_Type'Class;
      Item   : out    Instance
     ) is

      Trash : Ada.Streams.Stream_Element_Offset;
      Item_Elements : Header_Array;
   begin

      Ada.Streams.Read
        (Stream => Stream.all,
         Item   => Item_Elements,
         Last   => Trash
         );

      Item := To_Instance (Item_Elements);

   end Read;

A wise developer would probably check "Trash". But in my case I happen to
know (because I wrote them) that the streams used for this call will raise
exceptions rather than return a different Last than Item_Elements'Last.

If there's anything else you are curious about, just ask.

T.E.D.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own    




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

* Re: Ada.Streams examples
  1999-03-10  0:00 Ada.Streams examples Tom Moran
@ 1999-03-10  0:00 ` Steve Quinlan
  1999-03-10  0:00 ` dennison
  1 sibling, 0 replies; 16+ messages in thread
From: Steve Quinlan @ 1999-03-10  0:00 UTC (permalink / raw)


Tom Moran wrote:

> Could someone please point me to a text or tutorial or something on
> using Ada.Streams - in particular overriding the default 'Read etc.

If you're asking the mechanics of how to accomplish the override (vs.
how to implement it), the general concept is you define a subprogram
something like this for type foo;

procedure Foo_Write ( Stream access Root_Stream_Type'class;
                                  Item in Foo) is
--- code here
end Foo_Write;
for Foo'Write use Foo_Write;

As far as what to put into Foo_Write, you can do whatever you like --
implement it using the stream attributes of components of Foo,
re-ordering them or adding things or whatever. You could also define
your own way to convert Foo into an array of Stream Elements, and update
the Stream using the overriden Write procedure from Ada.Streams, which
given an array of stream elements will write it to the stream  (and
similarly for reading Foo).

There is a limited example of this in the  Barnes book 'Programming in
Ada95'.







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

* Re: Ada.Streams examples
  1999-03-10  0:00 ` dennison
  1999-03-10  0:00   ` Rex Reges
@ 1999-03-10  0:00   ` Tom Moran
  1999-03-10  0:00     ` dennison
  1999-03-11  0:00     ` Richard D Riehle
  1 sibling, 2 replies; 16+ messages in thread
From: Tom Moran @ 1999-03-10  0:00 UTC (permalink / raw)


  I'll take a look at Cohen (my son took my copy away to college).
Barnes example is pretty minimal.  I never would have figured this
stuff out just from the RM.  In addition to my questions, I'd like a
good place to send others.
  I want to do an S'Read routine for a large array.  I really don't
want to iteratively call Element'Read for each element.  Is there an
alternative to the usual Unchecked_Conversion, overlaying, etc to get
the data into my array?  If the array were in a Sequential_IO file I
could just do a single Read and the correct number of bytes would be
copied to the array - like an implicit Unchecked_Conversion.   
  What exactly is the use of S'Class'Read?  If I don't define my own,
the default dispatches to appropriate S'Read routines - mine or the
default ones.  If I do define my own S'Class'Read does that let me do
other than dispatching if I want (like other procedures that take a
classwide parameter)?  Does RM 13.13.2(38) mean that my S'Class'Read
will not be called for objects whose class is Son_Of_S?  ie, does
S'Class only apply "horizontally" to a single generation?
  The RM implies that an object's stream representation should be
similar to its in-memory representation (a generalization from
13.13.2(17)).  If I have an object which has a standard external
representation (a Windows bmp bitmap, for instance) but a slightly
different Ada representation in my program (discriminants, say), is it
better to convert the object on Write to the "standard" external form,
or to write it out as an Ada object as close as possible to its
internal, Ada, memory form?  This is not addressed in AQS - anybody
have any experience with these choices?




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

* Re: Ada.Streams examples
  1999-03-10  0:00   ` Tom Moran
  1999-03-10  0:00     ` dennison
@ 1999-03-11  0:00     ` Richard D Riehle
  1999-03-11  0:00       ` Steve Quinlan
  1 sibling, 1 reply; 16+ messages in thread
From: Richard D Riehle @ 1999-03-11  0:00 UTC (permalink / raw)


There is an interesting example of how to use Streams in the GNAT
compiler for Ada.Exceptions.  I post a fragment from my book, 
Object Technology in Ada that steals liberally from the GNAT package.

In the package specification for Ada.Exceptions the designer includes a context clause for Ada.Streams.  The
limited private type Exception_Occurrence has the full definiton as limited record.

type Exception_Occurrence
     (Max_Length : Nat := SSL.Exception_Msg_Max)
   is limited record
      Id         : Exception_Id;
      Msg_Length : Natural;
      Msg        : String (1 .. Max_Length);
   end record;

Elsewhere in the private part of the specification, two procedures are declared to provide Read and Write for
Exception_Occurrence.   It should be noted that 'Input and 'Output cannot be written for a limited private type
since assignment is not available.   It is possible to write those functions for Exception_Occurrence_Access which
is already defined in the Ada.Exceptions package.    For this discussion,  it should be enough to cover Read and
Write.  

procedure Exception_Occurrence_Read
     (Stream : access Ada.Streams.Root_Stream_Type'Class;
      Item   : out Exception_Occurrence);

procedure Exception_Occurrence_Write
     (Stream : access Ada.Streams.Root_Stream_Type'Class;
      Item   : in Exception_Occurrence);

for Exception_Occurrence'Read  use Exception_Occurrence_Read;
for Exception_Occurrence'Write use Exception_Occurrence_Write;

Note that Exception_Occurrence is a record.  Therfore, it is necessary to create Read and Write operations for it
since none currently exist.   Also, the creation of Read and Write procedures is not the same as overloading
existing subprograms.   You create a procedure with a name and the associate it with an attribute of 'Read or 'Write
through a representation specification.

Implementing code for Execption_Occurrence_Read and Execption_Occurrence_Write looks like this.

procedure Exception_Occurrence_Read
				(Stream : access Ada.Streams.Root_Stream_Type'Class;
				 Item   : out    Exception_Occurrence) is
	Name : String       := String'Input(Stream);
	Len  : Natural      := Natural'Input(Stream);
	Msg  : String       := String'Input(Stream);
begin
  Item.Id := Exception_Id (Internal_Exception (Name));
	if Msg'Length /= Len then
     raise Data_Error;
  end if;
      --  Silently truncate message if it does not fit
	Item.Msg_Length := Natural'Min (Len, Item.Max_Length);
	Item.Msg (1 .. Item.Msg_Length) := Msg (1 .. Item.Msg_Length);
end Exception_Occurrence_Read;

The reader should notice that the implementation of the Read operation takes advantage of the "Input attribute
already available for Standard types.   Now we show the code for implementing the 'Write.  It is even easier that
the code for the 'Read.

procedure Exception_Occurrence_Write
     		(Stream : access Ada.Streams.Root_Stream_Type'Class;
      		 Item   : in Exception_Occurrence) is
begin
      String'Output       (Stream, Exception_Name (Item.Id));
      Natural'Output      (Stream, Item.Msg_Length);
      String'Output       (Stream, Item.Msg (1 .. Item.Msg_Length));
end Exception_Occurrence_Write;

Hope this is helpful,

Richard Riehle
richard@adaworks.com
http://www.adaworks.com







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

* Re: Ada.Streams examples
  1999-03-11  0:00         ` Richard D Riehle
@ 1999-03-11  0:00           ` Steve Quinlan
  1999-03-12  0:00             ` Richard D Riehle
  0 siblings, 1 reply; 16+ messages in thread
From: Steve Quinlan @ 1999-03-11  0:00 UTC (permalink / raw)




Richard D Riehle wrote:

>  Perhaps I should have said, it is possible to override the Read and Write
>  operations so they behave exactly as you want them to. In fact, the
>  procedures Read and Write, in package Ada.Streams, are abstract so they
>  must be overridden. Note: we are not talking of Ada.Streams.Stream_IO.
>  We are talking about the parent package Ada.Streams (LRM 13.13.1).
>  Notice how useful this is in Ada.Exceptions from the GNAT compiler.
>
>  Richard

  OK, that's clearer. I understand that when you define a new stream type
derived from root_stream_class you have to implement the read and write
procedures that override Ada.Streams. But what GNAT did was to override the
'read and 'write attributes.







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

* Re: Ada.Streams examples
       [not found]       ` <36E7036B.EADEEA80@Boeing.com>
@ 1999-03-11  0:00         ` dennison
  0 siblings, 0 replies; 16+ messages in thread
From: dennison @ 1999-03-11  0:00 UTC (permalink / raw)


In article <36E7036B.EADEEA80@Boeing.com>,
  Rex Reges <Rex.R.Reges@Boeing.com> wrote:

> A container can be accessed by a single task at a time (only one packer at a
> time). However, two or more containers could be in the process of being filled
> at the same time, but only one task is allowed to do this work for any one
> container.  The honor system will be used, so a guard task isn't necessary.
>
> When the container is filled, then an exception should be raised. The choice
> then is to either use two containers or to use a bigger container.

Good. You are making things very easy for yourself. I needed something more
like a pipe, so it was considerably more difficult for me. All you'd have to
do in this case is create a simple buffer (an
Ada.Stream.Stream_Element_Array), and keep track of the read and write
pointers in the Stream's tagged type. I'd put a pointer to the buffer in the
stream type, and add a constructor procedure to allocate the array with a
given size and a destructor procedure to deallocate it:

private
   type Buffer_Ptr is access all Ada.Streams.Stream_Element_Array;
   type Stream is new Ada.Streams.Root_Stream_Type with record
      Head      : Index   := 1;
      Tail      : Index   := 1;
      Elements  : Buffer_Ptr;
   end record;


All you'd have to do after that is:  o	override "Write" to copy the given
stream elements into the buffer at the write pointer, and update the write
pointer.  o  override "Read" to copy the requested amount of stream elements
from the buffer at the read pointer, and update the read pointer.

If you wanted to get really sexy, I suppose you could implement "Open" calls
to prevent Reads from streams that are opened for Writes and the like.

T.E.D.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own    




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

* Re: Ada.Streams examples
  1999-03-10  0:00       ` Tom Moran
@ 1999-03-11  0:00         ` dennison
  1999-03-17  0:00           ` Tom Moran
  0 siblings, 1 reply; 16+ messages in thread
From: dennison @ 1999-03-11  0:00 UTC (permalink / raw)


In article <36e6fe8d.16020474@news.pacbell.net>,
  tmoran@bix.com (Tom Moran) wrote:
> >  o  Create a 'Write procedure for that bitmap type which converts the bitmap
> >to a bmp and does one massive Write call for the stream. The problem with
> >this approach is that if anyone ever wants to do a 'Write on a bitmap for any
> >reason, the'll get a BMP. You can't overload it to get a JPG or GIF or a
> >straight memory dump (which is what they might be expecting).
>   Someone could presumably do
>      type GIFED_Bitmap is new BMP with null record;
>      for GIFED_Bitmap'Write use  Convert_To_GIF_And_Write;
> Then internally a GIFED_Bitmap is the same as my BMP, and my routines
> all work on it, but when the user writes it he gets his
> Convert_To_GIF_And_Write instead of my BMP'Write.
> No?

Well, yes. But those are still different types, not the same type. I can think
of several other objections, but they all really boil down to...YUK!

> >  o  Create a Write_BMP and Read_BMP routine that take in files and bitmaps
as
> >parameters, and forget about streams.
>   But with the BMP'Write I separate the file from the conversion, so
> the result of the conversion could be handed to a called C routine,
> say.  That seems to me a pretty strong argument for BMP'Write instead
> of BMP_Write.

That is true. If there are several different sources you might want to route
your output to other than just disk files, that is a point in the favor of
using 'Write for the conversion. But note that in the case you give the C
routine will have to be able to handle the data in the way 'Write will give
it. If you write both 'Write and the stream's Write (which internally
interfaces to the C) then you should be ok. You still have the problem of
some goober comming along and trying to do an Integer'Write to your BMP
stream, but perhaps that's not a big deal in your application.



T.E.D.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own    




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

* Re: Ada.Streams examples
  1999-03-11  0:00     ` Richard D Riehle
@ 1999-03-11  0:00       ` Steve Quinlan
  1999-03-11  0:00         ` Richard D Riehle
  0 siblings, 1 reply; 16+ messages in thread
From: Steve Quinlan @ 1999-03-11  0:00 UTC (permalink / raw)


Richard D Riehle wrote:

>  Note that Exception_Occurrence is a record.  Therfore, it is necessary to create Read and Write operations for it
> since none currently exist.

Why would there not be read and write operations available? Those attributes are supported for composite types, aren't
they?





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

* Re: Ada.Streams examples
  1999-03-11  0:00       ` Steve Quinlan
@ 1999-03-11  0:00         ` Richard D Riehle
  1999-03-11  0:00           ` Steve Quinlan
  0 siblings, 1 reply; 16+ messages in thread
From: Richard D Riehle @ 1999-03-11  0:00 UTC (permalink / raw)


In article <36E7EFCF.82A87270@nospam.lmco.com>,
	Steve Quinlan <steven.quinlan@nospam.lmco.com> wrote:

>Richard D Riehle wrote:
>
>>  Note that Exception_Occurrence is a record.  Therfore, it is necessary
to create Read and Write operations for it
>> since none currently exist.
>
>Why would there not be read and write operations available? Those
attributes are supported for composite types, aren't
>they?
>
 Perhaps I should have said, it is possible to override the Read and Write
 operations so they behave exactly as you want them to. In fact, the
 procedures Read and Write, in package Ada.Streams, are abstract so they    
 must be overridden. Note: we are not talking of Ada.Streams.Stream_IO. 
 We are talking about the parent package Ada.Streams (LRM 13.13.1). 
 Notice how useful this is in Ada.Exceptions from the GNAT compiler.  

 Richard
 




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

* Re: Ada.Streams examples
  1999-03-11  0:00           ` Steve Quinlan
@ 1999-03-12  0:00             ` Richard D Riehle
  0 siblings, 0 replies; 16+ messages in thread
From: Richard D Riehle @ 1999-03-12  0:00 UTC (permalink / raw)


In article <36E82E5B.6C1B4050@nospam.lmco.com>,
	Steve Quinlan <steven.quinlan@nospam.lmco.com> wrote:

>  OK, that's clearer. I understand that when you define a new stream type
>derived from root_stream_class you have to implement the read and write
>procedures that override Ada.Streams. But what GNAT did was to override the
>'read and 'write attributes.

 That is exactly right.  Notice how the overriding was done.  First
 the author coded an procedure specification,

 procedure Exception_Occurrence_Read
     (Stream : access Ada.Streams.Root_Stream_Type'Class;
      Item   : out Exception_Occurrence);

 The she/he attached that procedure to the 'Read attribute.  

for Exception_Occurrence'Read  use Exception_Occurrence_Read;

 This means that there is now a special version of 'Read for
 Exception_Occurrence.  This is important because the author 
 wanted 'Read to behave in a very special way.  The final code
 for implementing the procedure looks like this,

procedure Exception_Occurrence_Read
				(Stream : access Ada.Streams.Root_Stream_Type'Class;
				 Item   : out    Exception_Occurrence) is
	Name : String       := String'Input(Stream);
	Len  : Natural      := Natural'Input(Stream);
	Msg  : String       := String'Input(Stream);
begin
  Item.Id := Exception_Id (Internal_Exception (Name));
	if Msg'Length /= Len then
     raise Data_Error;
  end if;
      --  Silently truncate message if it does not fit
	Item.Msg_Length := Natural'Min (Len, Item.Max_Length);
	Item.Msg (1 .. Item.Msg_Length) := Msg (1 .. Item.Msg_Length);
end Exception_Occurrence_Read;

This version will behave as one would expect for the data type.  This
one reason why Ada.Streams is important: so the designer can create
well-behaved 'Read and 'Write attributes for composite data types.
Imagine, for example, that you wanted a 'Read and 'Write for a
full data structure such as a stack.  You would certainly want to code
your own version of those attributes.  It would be a far more complex
procedure than the ones we have looked at so far.  But it would be 
possible if you wanted to take the trouble.

As another simpler example, we override the abstract Read for a
brand new type,

with Ada.Streams;
package Stream_05 is

  type My_Stream is tagged record
     Id  : Natural := 0;
  end record;
  
  procedure My_Stream_Read 
      (Stream : access Ada.Streams.Root_Stream_Type'Class;
       Item   : out My_Stream);
       
  for My_Stream'Read use My_Stream_Read;
  
  -- also override Write for a complete implementation  

end Stream_05;

The coding of My_Stream_Read is left as an excercise. You may follow the
pattern shown in the Exception_Occurrence example. Now we create a little
test program.  

with Stream_05;                                    --  1
with Ada.Streams.Stream_IO;                        --  2
use  Ada;                                          --  3
procedure Test_Stream_05 is                        --  4
  The_Stream : Streams.Stream_IO.Stream_Access;    --  5
  Data : Stream_05.My_Stream;                      --  6
  Class_Data : Stream_IO.My_Stream'Class := Data;  --  7
begin                                              --  8
  -- First version for overriding Read             --  9
  Data := Stream_05.My_Stream'Input(The_Stream);   -- 10 
  -- Second version of using the Read              -- 11
  Stream_05.My_Stream'Read(The_Stream, Data);      -- 12
    -- Third version of using the Read             -- 13
  Class_Data := Stream_05.                         -- 14
                My_Stream'Class'Input(The_Stream); -- 15
end Test_Stream_05;                                -- 16

The first version, on line 10, shows how we can use this
with the 'Input statement.   The version on line 12 shows
how we use it with a 'Read statement.   The version on lines
14-15 show how to call it with a 'Class'Input.  Note that 
the 'Class'Input version reads the tag and is dispatching.

The rules for each type of call are clearly spelled out in
ALRM 13.13.2.  Congratualtions to whoever wrote that section
of the ALRM.  They did a good job of explaining the mechanism.

Richard Riehle
richard@adaworks.com
http://www.adaworks.com




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

* Re: Ada.Streams examples
  1999-03-11  0:00         ` dennison
@ 1999-03-17  0:00           ` Tom Moran
  0 siblings, 0 replies; 16+ messages in thread
From: Tom Moran @ 1999-03-17  0:00 UTC (permalink / raw)


>>   Someone could presumably do
>>      type GIFED_Bitmap is new BMP with null record;
>>      for GIFED_Bitmap'Write use  Convert_To_GIF_And_Write;
>> Then internally a GIFED_Bitmap is the same as my BMP, and my routines
>> all work on it, but when the user writes it he gets his
>> Convert_To_GIF_And_Write instead of my BMP'Write.

> I can think of several other objections, but they all really boil down to...YUK!
  He could certainly write his own Write_As_Gif(X : in BMP) and call
it directly.  Or I could make an abstract 'Write (or could I?) for BMP
and a higher level 
  type External_Form_Is_BMP is new BMP with null record;
with a 'Write that generates .bmp, and he could make instead
  type External_Form_Is_GIF is new BMP with null record;
etc.  
  I guess I don't react YUK.  A multiplatform GIF image seems to me
legitimately a higher abstraction level than a Windows DIBitmap/.bmp
file.






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

end of thread, other threads:[~1999-03-17  0:00 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-03-10  0:00 Ada.Streams examples Tom Moran
1999-03-10  0:00 ` Steve Quinlan
1999-03-10  0:00 ` dennison
1999-03-10  0:00   ` Rex Reges
1999-03-10  0:00     ` dennison
     [not found]       ` <36E7036B.EADEEA80@Boeing.com>
1999-03-11  0:00         ` dennison
1999-03-10  0:00   ` Tom Moran
1999-03-10  0:00     ` dennison
1999-03-10  0:00       ` Tom Moran
1999-03-11  0:00         ` dennison
1999-03-17  0:00           ` Tom Moran
1999-03-11  0:00     ` Richard D Riehle
1999-03-11  0:00       ` Steve Quinlan
1999-03-11  0:00         ` Richard D Riehle
1999-03-11  0:00           ` Steve Quinlan
1999-03-12  0:00             ` Richard D Riehle

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