comp.lang.ada
 help / color / mirror / Atom feed
* S'Write and How To Count Bytes
@ 2000-09-30  0:00 Marin David Condic
  2000-10-01  0:00 ` David C. Hoos, Sr.
                   ` (2 more replies)
  0 siblings, 3 replies; 29+ messages in thread
From: Marin David Condic @ 2000-09-30  0:00 UTC (permalink / raw)


Suppose I have a type something like this:

    type My_Record is record
        A_String    : Unbounded_String := Null_Unbounded_String ;
    end record ;

In theory, I should be able to create an object that is derived from
Ada.Streams.Root_Stream_Type which has a Read and Write procedure that
will allow me to create a call such as:

    My_Record'Write (Ptr, A_Record) ;

where Ptr is a pointer to my derived Root_Stream_Type object. Now here's
where it gets fun:

The object derived from Root_Stream_Type is going to contain some
version of a Stream_Element_Array. Possibly dynamically allocated. The
Write procedure that I create for the Root_Stream_Type is going to get
automagically called with a Stream_Element_Array parameter, from which
you could determine the size, allocate what you need for a buffer and
attach it to the Root_Stream_Type. That buffer can then be sent
somewhere or used in some other manner.

The problem is this: What if you want the record to contain the number
of bytes that it converts to so that the number ends up in the stream?
You can't easily determine how many bytes there will be in the record
nor can you determine what the 'Write is really going to produce. You
could possibly retain the size information in your Root_Stream_Type
after the conversion, but by then its too late. You already converted it
and if you had a "Count" field in the record, its value is probably dead
wrong. You could convert it to the stream once, interrogate the
Root_Stream_Type you built to determine the number of bytes in it, then
include that byte count in your record and convert it all over again.
That seems a little inefficient.

Is there any good way of determining in advance how many bytes you are
going to get when converting an object to a stream?

MDC
--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================






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

* Re: S'Write and How To Count Bytes
  2000-09-30  0:00 S'Write and How To Count Bytes Marin David Condic
@ 2000-10-01  0:00 ` David C. Hoos, Sr.
  2000-10-02  0:00   ` Marin David Condic
  2000-10-02  0:00   ` Dr. Joachim Schr�er
  2000-10-02  0:00 ` David C. Hoos, Sr.
  2000-10-02  6:58 ` tmoran
  2 siblings, 2 replies; 29+ messages in thread
From: David C. Hoos, Sr. @ 2000-10-01  0:00 UTC (permalink / raw)


If your record contains an unbounded string, I would in the My_Record'Write
procedure convert the unbounded string to a Standard.String, and write its
length to the stream with Natural'Write, followed by a call to String'Write.
This will put the length of the string on the stream, followed by the
string itself.

Then, the My_Record'Read procedure would read the length from the stream,
using Natural'Read, use that length to declare a string of the proper size
(in a declare block), then read the string with String'Read.
Finally, you would convert the string to the unbounded string component in
your My_Record'Read's out parameter of type My_Record.


Marin David Condic <mcondic.nospam@acm.org> wrote in message
news:39D6891A.7DC448B6@acm.org...
> Suppose I have a type something like this:
>
>     type My_Record is record
>         A_String    : Unbounded_String := Null_Unbounded_String ;
>     end record ;
>
> In theory, I should be able to create an object that is derived from
> Ada.Streams.Root_Stream_Type which has a Read and Write procedure that
> will allow me to create a call such as:
>
>     My_Record'Write (Ptr, A_Record) ;
>
> where Ptr is a pointer to my derived Root_Stream_Type object. Now here's
> where it gets fun:
>
> The object derived from Root_Stream_Type is going to contain some
> version of a Stream_Element_Array. Possibly dynamically allocated. The
> Write procedure that I create for the Root_Stream_Type is going to get
> automagically called with a Stream_Element_Array parameter, from which
> you could determine the size, allocate what you need for a buffer and
> attach it to the Root_Stream_Type. That buffer can then be sent
> somewhere or used in some other manner.
>
> The problem is this: What if you want the record to contain the number
> of bytes that it converts to so that the number ends up in the stream?
> You can't easily determine how many bytes there will be in the record
> nor can you determine what the 'Write is really going to produce. You
> could possibly retain the size information in your Root_Stream_Type
> after the conversion, but by then its too late. You already converted it
> and if you had a "Count" field in the record, its value is probably dead
> wrong. You could convert it to the stream once, interrogate the
> Root_Stream_Type you built to determine the number of bytes in it, then
> include that byte count in your record and convert it all over again.
> That seems a little inefficient.
>
> Is there any good way of determining in advance how many bytes you are
> going to get when converting an object to a stream?
>
> MDC
> --
> ======================================================================
> Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
> Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
> Visit my web site at:  http://www.mcondic.com/
>
>     "Giving money and power to Government is like giving whiskey
>     and car keys to teenage boys."
>
>         --   P. J. O'Rourke
> ======================================================================
>
>





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

* Re: S'Write and How To Count Bytes
  2000-10-01  0:00 ` David C. Hoos, Sr.
  2000-10-02  0:00   ` Marin David Condic
@ 2000-10-02  0:00   ` Dr. Joachim Schr�er
  2000-10-02  0:00     ` Marin David Condic
  1 sibling, 1 reply; 29+ messages in thread
From: Dr. Joachim Schr�er @ 2000-10-02  0:00 UTC (permalink / raw)


I have not thought about the original question but there is
a more elegant solution for your description.

The 'read, 'write attributes are for constrained types.
For unconstrained types (including tagged types/classwide types)
there exist the 'input, 'output attributes. Note, that 'input
is a function. If you want to overwrite 'input, 'output you just
have to overwrite 'read, 'write cause they are used by the former.

For this and input/output of access objects/linked datastructures
you should look into the relevant chapter of Norman Cohens
Ada95 version of "Ada as a second language" or into the Rationale,
chapter A.4.1.

 J. Schroer


David C. Hoos, Sr. <david.c.hoos.sr@ada95.com> schrieb in im Newsbeitrag:
<hXTB5.64979$Ao1.5807473@newsrump.sjc.telocity.net>...
> If your record contains an unbounded string, I would in the
My_Record'Write
> procedure convert the unbounded string to a Standard.String, and write its
> length to the stream with Natural'Write, followed by a call to
String'Write.
> This will put the length of the string on the stream, followed by the
> string itself.
>
> Then, the My_Record'Read procedure would read the length from the stream,
> using Natural'Read, use that length to declare a string of the proper size
> (in a declare block), then read the string with String'Read.
> Finally, you would convert the string to the unbounded string component in
> your My_Record'Read's out parameter of type My_Record.
>
>
> Marin David Condic <mcondic.nospam@acm.org> wrote in message
> news:39D6891A.7DC448B6@acm.org

snip
...









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

* Re: S'Write and How To Count Bytes
  2000-10-02  0:00   ` Marin David Condic
@ 2000-10-02  0:00     ` Ted Dennison
  2000-10-02  0:00       ` tmoran
  2000-10-03  0:00       ` Robert A Duff
  0 siblings, 2 replies; 29+ messages in thread
From: Ted Dennison @ 2000-10-02  0:00 UTC (permalink / raw)


In article <39D88ACE.92DF8897@acm.org>,
  Marin David Condic <mcondic.nospam@acm.org> wrote:
> Well, there are a couple of questions here. One if which is "How does
> 'Write" normally handle an Unbounded_String or any other private type
> for that matter?" The ARM says they are defined for any non-limited

If they are non-composite types, they get their bit pattern written out.
If they are compositie types, 'Write gets called for each component.
This can be kinda nasty when you've got a big array and 'Write for that
stream is not entirely trivial.

> type (ARM 13.13.2{36}) but I could easily see a private type (or any
> type) containing Access variables - no mention of that. It mentions

The value of the access type (not what it points to) gets written. This
is almost certianly *not* what you want. In that case the author of the
private type needs to make their own 'Write for that type which does
something more sensible (eg: 'Write on Object.all).

> Obviously, transmitting Access variables is *not* a good idea. (What
> if I store an unbounded string using Stream_IO? Is it going to come
> back properly, or will I have just stored a now-useless access
> variable that used to point to the string?)

I'm not sure if implementors are required to make 'Write on unbounded
strings (or bounded ones for that matter) do anything sensible. I don't
see anything in the LRM about it, so I'd guess not. You should probably
convert them to strings and do a String'Write (or 'Output).

>
> Unbounded_Strings. In other words, I need to somehow get the number of
> bytes I'm transmitting into the stream and I can't count on the
> listener at the other end to be using Ada or anything else. (The
> device expects one of several messages with varying lengths - it needs
> the number of bytes as the first datum to correctly read all the data
> for the message before attempting to process it.) I believe I can use
> the 'Read and 'Write attributes to correctly get the individual data
> pieces into the stream, but I need to know how many bytes that is
> going to be before putting it in the stream. So far as I can tell,
> there is no way to do this except convert it to a stream, count the
> bytes that turned into, insert the byte count in the record, then
> convert it to a stream again. Awfully wasteful!

I had a similar need. What I did is made my custom stream require an
"Open" and "Close" (primitives on the stream type) around a series of
writes. This isn't that heinous; Ada.Streams.Text_IO has a similar
restriction. Open leaves a 4 byte (I guess 2 would probably suffice)
space at the front of the buffer for a count. Close calculates the
number of bytes between the count bytes and the end of the stream data,
and puts that value into the count bytes.


> Maybe for Ada0x, there should be an attribute T'Stream_Size and/or
> T'Class'Stream_Size. Not sure that this would not simply have to
> degenerate to converting everything and counting it in the background
> though.
The problem with this is that since users can make their own 'Write
attribute routines, there is no way to calculate this short of actually
performing the writes. You might as well just do it yourself.

--
T.E.D.

http://www.telepath.com/~dennison/Ted/TED.html


Sent via Deja.com http://www.deja.com/
Before you buy.




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

* Re: S'Write and How To Count Bytes
  2000-10-02  0:00     ` Ted Dennison
@ 2000-10-02  0:00       ` tmoran
  2000-10-02  0:00         ` tmoran
  2000-10-02  0:00         ` Marin David Condic
  2000-10-03  0:00       ` Robert A Duff
  1 sibling, 2 replies; 29+ messages in thread
From: tmoran @ 2000-10-02  0:00 UTC (permalink / raw)


You can of course have two different "new Root_Stream_Type"s, one
of which merely adds to a counter without actually copying data,
and the other actually does the data copy.  This is certainly
faster for simple but wide things.

But

>The problem with this is that since users can make their own 'Write
>attribute routines, there is no way to calculate this short of actually
>performing the writes.
  So a complex composite structure necessarily makes many subroutine
calls, adding up to a lot of time even if each call itself is fast.

>You see the double-conversion of the record to a stream. That's got to be
>inefficient. If there were some way of knowing in advance how many bytes the
>record was going to take up in the stream, we could save that
>double-conversion.
  I still don't understand.  Is each Integer'Write generating a call to
the IO routine, or is it writing into a buffer, which will be passed
to the IO routine when it contains the entire composite record?  In
the latter case, which I assume to be what you mean, keep a running
total of the number of bytes in the buffer, then
Send(Byte_Count, The_Resulting_Stream_Element_Array)
or do an Integer'Write(S, Byte_Count) to
Byte_Count_Header : Stream_Element_Array(1 .. 4);
and replace a junk initial integer with Buffer(1 .. 4) := Byte_Count_Header;

  Another option of course would be to figure out the maximum size, write
into that size buffer, possibly leaving unfilled junk on the end, and
pass the fixed size buffer to your output routine.  It knows the size so
it can checksum and send the whole fixed size block.  The reader will use
'Read and get the actual data back and never even notice the trailing pads.

>You can't really use the 'Write in that case because you're counting on your
>representation to handle how it looks in the stream. (You might get there by
>accident, but when you're building a communication link to the outside world,
>you've *really* got to be sure it gets into that stream *exactly* the way you
>said it would or you're going to have some really upset people at the other end
>of the wire. Compiler changes could really mess you up there.)
   It seems to me this indicates that Stream_IO may simply be
inappropriate for such an application.  The only way you can really know
where the bytes are is via record rep clauses, or by writing your own
'Writes to handle everything in your records.  If you depend on the
compiler, even for Integer'Write, some compiler might some day decide to
write integers in Roman numeral form, or in some error-correcting code
expanded form, or whatever, and there goes your app.  My understanding
is that the only thing you can depend on from the compiler is the
*sequence* of 'Write calls.




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

* Re: S'Write and How To Count Bytes
  2000-10-02  0:00       ` tmoran
@ 2000-10-02  0:00         ` tmoran
  2000-10-02  0:00           ` Marin David Condic
  2000-10-02  0:00           ` Ted Dennison
  2000-10-02  0:00         ` Marin David Condic
  1 sibling, 2 replies; 29+ messages in thread
From: tmoran @ 2000-10-02  0:00 UTC (permalink / raw)


How about dropping the initial byte count and use an end-of-record
indicator instead, like LF in Text_IO?




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

* Re: S'Write and How To Count Bytes
  2000-10-02  0:00         ` tmoran
  2000-10-02  0:00           ` Marin David Condic
@ 2000-10-02  0:00           ` Ted Dennison
  1 sibling, 0 replies; 29+ messages in thread
From: Ted Dennison @ 2000-10-02  0:00 UTC (permalink / raw)


In article <ls5C5.275608$i5.3821851@news1.frmt1.sfba.home.com>,
  tmoran@bix.com wrote:
> How about dropping the initial byte count and use an end-of-record
> indicator instead, like LF in Text_IO?
>

I believe he had an external hardware device whose command spec he had
to match.

Of course that's a whole other can of worms. You have no control over
how the various 'Write's in your system represent their objects (unless
you use only ones that you wrote yourself).

--
T.E.D.

http://www.telepath.com/~dennison/Ted/TED.html


Sent via Deja.com http://www.deja.com/
Before you buy.




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

* Re: S'Write and How To Count Bytes
  2000-10-01  0:00 ` David C. Hoos, Sr.
@ 2000-10-02  0:00   ` Marin David Condic
  2000-10-02  0:00     ` Ted Dennison
  2000-10-02  0:00   ` Dr. Joachim Schr�er
  1 sibling, 1 reply; 29+ messages in thread
From: Marin David Condic @ 2000-10-02  0:00 UTC (permalink / raw)


"David C. Hoos, Sr." wrote:

> If your record contains an unbounded string, I would in the My_Record'Write
> procedure convert the unbounded string to a Standard.String, and write its
> length to the stream with Natural'Write, followed by a call to String'Write.
> This will put the length of the string on the stream, followed by the
> string itself.
>
> Then, the My_Record'Read procedure would read the length from the stream,
> using Natural'Read, use that length to declare a string of the proper size
> (in a declare block), then read the string with String'Read.
> Finally, you would convert the string to the unbounded string component in
> your My_Record'Read's out parameter of type My_Record.

Well, there are a couple of questions here. One if which is "How does 'Write"
normally handle an Unbounded_String or any other private type for that matter?"
The ARM says they are defined for any non-limited type (ARM 13.13.2{36}) but I
could easily see a private type (or any type) containing Access variables - no
mention of that. It mentions Elementary types, Array types, Record types, but
not Access types. (Or is Access an Elementary type? If so, its still a special
case) Obviously, transmitting Access variables is *not* a good idea. (What if I
store an unbounded string using Stream_IO? Is it going to come back properly, or
will I have just stored a now-useless access variable that used to point to the
string?)

The other question is: "What if you extended the type and still wanted to handle
the general case with dispatching => T'Class'Write?" That's really what I want
to do - not so much a specific case of Unbounded_Strings. In other words, I need
to somehow get the number of bytes I'm transmitting into the stream and I can't
count on the listener at the other end to be using Ada or anything else. (The
device expects one of several messages with varying lengths - it needs the
number of bytes as the first datum to correctly read all the data for the
message before attempting to process it.) I believe I can use the 'Read and
'Write attributes to correctly get the individual data pieces into the stream,
but I need to know how many bytes that is going to be before putting it in the
stream. So far as I can tell, there is no way to do this except convert it to a
stream, count the bytes that turned into, insert the byte count in the record,
then convert it to a stream again. Awfully wasteful!

Maybe for Ada0x, there should be an attribute T'Stream_Size and/or
T'Class'Stream_Size. Not sure that this would not simply have to degenerate to
converting everything and counting it in the background though.

Thanks for the help.

MDC
--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================






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

* Re: S'Write and How To Count Bytes
  2000-10-02  6:58 ` tmoran
@ 2000-10-02  0:00   ` Marin David Condic
  0 siblings, 0 replies; 29+ messages in thread
From: Marin David Condic @ 2000-10-02  0:00 UTC (permalink / raw)


tmoran@bix.com wrote:

> > Is there any good way of determining in advance how many bytes you are
> > going to get when converting an object to a stream?
>   I don't think I understand.  Why not
>   type Buffer_Type is new Root_Stream_Type with record
>     Last : Natural := 0;
>     Data : Stream_Element_Array(1 .. 1000);
>   end record;
>   Then each 'write can append its stuff to Data and increment Last
> and when they have all finished you have a count and a Stream_Element_Array
> to pass to your IO output routine.
> -----------------

Well, that's pretty much what I said was one possible solution. Convert it to a
stream, counting the bytes as you go. But suppose your record type looks a
little more like this:

type Some_Rec is tagged record
    Number_Of_Bytes_To_Pick_Up_Off_The_Wire : Natural ;
    Some_Piece_Of_Data : Any_Type_You_Like ;
end record ;

In the application at hand, I've got a listener at the other end of the wire
expecting to see a count of how many bytes to pick up before processing. Before
sending down the wire, I've got to fill in that number. I'd also like to do it
in such a way that I can manage it for Some_Rec'Class so that by dispatching,
all the other types derived from it are correctly handled.

Now with your Buffer_Type I could do Some_Rec'Class'Write (Buff_Ptr, My_Rec);
Then, (if you were a really swell guy and gave me all the right calls) I could
go:

My_Rec.Number_Of_Bytes_To_Pick_Up_Off_The_Wire := Toms_Pack.Bytes_In_Buffer ;
Toms_Pack.Discard_Buffer (Buffer_Object) ;
Some_Rec'Class'Write (Buff_Ptr, My_Rec) ;
Toms_Pack.Go_Ahead_And_Send_It_Now (Buffer_Object) ;

Did I explain that better this time? Hope so.

You see the double-conversion of the record to a stream. That's got to be
inefficient. If there were some way of knowing in advance how many bytes the
record was going to take up in the stream, we could save that
double-conversion.

I'd like to be able to do this with some version of My_Rec'Size but I've been
up and down this direction a thousand times and can never arrive at a
satisfactory answer. You've got to be able to control representation, alignment
of type extensions and remove the tag in the process of converting to a stream.
You can't really use the 'Write in that case because you're counting on your
representation to handle how it looks in the stream. (You might get there by
accident, but when you're building a communication link to the outside world,
you've *really* got to be sure it gets into that stream *exactly* the way you
said it would or you're going to have some really upset people at the other end
of the wire. Compiler changes could really mess you up there.)

If you can't get there with representation clauses, you could conceivably get
there with 'Write and making sure you control the sizes of the elementary
types. I think I've got enough guarantees from the ARM with respect to
elementary types that if I stick to things like UInt_16 and SInt_32 and other
things that never pack down below the size of a byte, that the 'Write attribute
will give you all this stuff packed end-to-end, pretty much like you'd
anticipate. Hence your message representation is controlled by the 'Write.

This is, of course, inherently slow in comparison to using a representation
clause controlled record and a byte array overlay, but for this app, I'm not on
a tiny little processor with no memory and 90% CPU utilization and I've got
maybe 500mSec to get the job done. So I can eat the overhead of a bazillion
tiny little subprogram calls to get the data in the stream. But I'd sure hate
to have to eat that overhead *twice*!

Thanks for the input.

MDC
--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================






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

* Re: S'Write and How To Count Bytes
  2000-10-02  0:00   ` Dr. Joachim Schr�er
@ 2000-10-02  0:00     ` Marin David Condic
  2000-10-06  0:00       ` Charles Hixson
  0 siblings, 1 reply; 29+ messages in thread
From: Marin David Condic @ 2000-10-02  0:00 UTC (permalink / raw)


"Dr. Joachim Schr�er" wrote:

> The 'read, 'write attributes are for constrained types.
> For unconstrained types (including tagged types/classwide types)
> there exist the 'input, 'output attributes. Note, that 'input
> is a function. If you want to overwrite 'input, 'output you just
> have to overwrite 'read, 'write cause they are used by the former.

I've used the 'Input and 'Output in the process of saving and reloading things
from a file. It works nicely. However, in this case, I can't have all the dope
information in the output. See some of the other posts in this thread where I
explain it in a little more detail. Also, even with the 'Input and 'Output, you
don't seem to have any means of determining in advance how big a stream of bytes
you will produce from the operation. I don't see an obvious answer and perhaps
no good one exists. Probably you would have to convert the data to get the size,
then convert it again to get the size into the output.

MDC
--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================






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

* Re: S'Write and How To Count Bytes
  2000-09-30  0:00 S'Write and How To Count Bytes Marin David Condic
  2000-10-01  0:00 ` David C. Hoos, Sr.
@ 2000-10-02  0:00 ` David C. Hoos, Sr.
  2000-10-02  6:58 ` tmoran
  2 siblings, 0 replies; 29+ messages in thread
From: David C. Hoos, Sr. @ 2000-10-02  0:00 UTC (permalink / raw)


In my original answer, I gave a solution specific to your example, but there
is another technique I use for more general cases.

This technique uses a package I call Stream_Element_array_Streams, which
reads or writes to a region of memory defined by two parameters of
System.Address type.  The package has a procedure called Allow_Access
which defines the two address parameters, and whether the operation for
which
access is allowed is Read or Write.

This package maintains an index (initialized to 1 by the Allow_Access
procedure),
pointing to the next element on which the allowed operation would take
place.

Thus, after writing to this memory stream, the Index function of the package
can be
called to ascertain the number of bytes written.

The actual write to the file or communications channel, can be done with
Stream_Element_Array'Write, having been preceded by a call to Natural'Write
to
put the size on the stream first.

One situation for which I use this technique is the reading of DIS PDUs from
a UDP
port, where the Ada type has discriminants whose values are defined by the
values
of octets at a fixed offset from the start of the PDU.  Thus, I read the PDU
using a
package which delivers me a stream_element_array containing all of the
octets of
the  UDP packet. Then, I declare the object with the discriminant obtained
from the
appropriate elements of that array, and finally read from the raw memory
array into
the Ada (tagged) type, using my Stream_Element_Array_Streams package.

The reason I did not suggest the use of 'Input and 'Output (as suggested by
Dr. Schroer) is that you indicated only that you wanted the _length_ of the
stream
of bytes produced by the 'Write, whereas 'Input and 'Output write the 'First
and 'Last
for arrays, and in general insert all discriminants and/or bounds into the
stream.

I know this has been wordy, but I hope it helps.

> ----- Original Message -----
> From: "Marin David Condic" <mcondic.nospam@acm.org>
> To: "David C. Hoos, Sr." <david.c.hoos.sr@ada95.com>
> Sent: Monday, October 02, 2000 7:37 AM
> Subject: RE: S'Write and How To Count Bytes

> Well, there are a couple of questions here. One if which is "How does
> 'Write" normally handle an Unbounded_String or any other private type for
> that matter?" The ARM says they are defined for any non-limited type (ARM
> 13.13.2{36}) but I could easily see a private type (or any type)
containing
> Access variables - no mention of that. It mentions Elementary types, Array
> types, Record types, but not Access types. (Or is Access an Elementary
type?
> If so, its still a special case) Obviously, transmitting Access variables
is
> *not* a good idea. (What if I store an unbounded string using Stream_IO?
Is
> it going to come back properly, or will I have just stored a now-useless
> access variable that used to point to the string?)

> The other question is: "What if you extended the type and still wanted to
> handle the general case with dispatching => T'Class'Write?" That's really
> what I want to do - not so much a specific case of Unbounded_Strings. In
> other words, I need to somehow get the number of bytes I'm transmitting
into
> the stream and I can't count on the listener at the other end to be using
> Ada or anything else. (The device expects one of several messages with
> varying lengths - it needs the number of bytes as the first datum to
> correctly read all the data for the message before attempting to process
> it.) I believe I can use the 'Read and 'Write attributes to correctly get
> the individual data pieces into the stream, but I need to know how many
> bytes that is going to be before putting it in the stream. So far as I can
> tell, there is no way to do this except convert it to a stream, count the
> bytes that turned into, insert the byte count in the record, then convert
it
> to a stream again. Awfully wasteful!

> Maybe for Ada0x, there should be an attribute T'Stream_Size and/or
> T'Class'Stream_Size. Not sure that this would not simply have to
degenerate
> to converting everything and counting it in the background though.
>
> Thanks for the help.

> MDC

>> -----Original Message-----
>> From: David C. Hoos, Sr. [mailto:david.c.hoos.sr@ada95.com]
>> Sent: Monday, October 02, 2000 12:15 AM
>> To: mcondic.nospam@acm.org
>> Subject: Re: S'Write and How To Count Bytes

>> If your record contains an unbounded string, I would in the
My_Record'Write
>> procedure convert the unbounded string to a Standard.String, and write
its
>> length to the stream with Natural'Write, followed by a call to
String'Write.
>> This will put the length of the string on the stream, followed by the
>> string itself.

>> Then, the My_Record'Read procedure would read the length from the stream,
>> using Natural'Read, use that length to declare a string of the proper
size
>> (in a declare block), then read the string with String'Read.
>> Finally, you would convert the string to the unbounded string component
in
>> your My_Record'Read's out parameter of type My_Record.

"Marin David Condic" <mcondic.nospam@acm.org> wrote in message
news:39D6891A.7DC448B6@acm.org...
>>> Suppose I have a type something like this:
>>>
>>>     type My_Record is record
>>>         A_String    : Unbounded_String := Null_Unbounded_String ;
>>>     end record ;
>>>
>>> In theory, I should be able to create an object that is derived from
>>> Ada.Streams.Root_Stream_Type which has a Read and Write procedure that
>>> will allow me to create a call such as:
>>>
>>>     My_Record'Write (Ptr, A_Record) ;
>>>
>>> where Ptr is a pointer to my derived Root_Stream_Type object. Now here's
>>> where it gets fun:
>>>
>>> The object derived from Root_Stream_Type is going to contain some
>>> version of a Stream_Element_Array. Possibly dynamically allocated. The
>>> Write procedure that I create for the Root_Stream_Type is going to get
>>> automagically called with a Stream_Element_Array parameter, from which
>>> you could determine the size, allocate what you need for a buffer and
>>> attach it to the Root_Stream_Type. That buffer can then be sent
>>> somewhere or used in some other manner.
>>>
>>> The problem is this: What if you want the record to contain the number
>>> of bytes that it converts to so that the number ends up in the stream?
>>> You can't easily determine how many bytes there will be in the record
>>> nor can you determine what the 'Write is really going to produce. You
>>> could possibly retain the size information in your Root_Stream_Type
>>> after the conversion, but by then its too late. You already converted it
>>> and if you had a "Count" field in the record, its value is probably dead
>>> wrong. You could convert it to the stream once, interrogate the
>>> Root_Stream_Type you built to determine the number of bytes in it, then
>>> include that byte count in your record and convert it all over again.
>>> That seems a little inefficient.
>>>
>>> Is there any good way of determining in advance how many bytes you are
>>> going to get when converting an object to a stream?
>>>
>>> MDC
>>> --
>>> ======================================================================
>>> Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
>>> Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
>>> Visit my web site at:  http://www.mcondic.com/
>>>
>>>     "Giving money and power to Government is like giving whiskey
>>>     and car keys to teenage boys."
>>>
>>>         --   P. J. O'Rourke
>>> ======================================================================
>>>
>>>






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

* Re: S'Write and How To Count Bytes
  2000-10-02  0:00       ` tmoran
  2000-10-02  0:00         ` tmoran
@ 2000-10-02  0:00         ` Marin David Condic
  1 sibling, 0 replies; 29+ messages in thread
From: Marin David Condic @ 2000-10-02  0:00 UTC (permalink / raw)


tmoran@bix.com wrote:

>   I still don't understand.  Is each Integer'Write generating a call to
> the IO routine, or is it writing into a buffer, which will be passed
> to the IO routine when it contains the entire composite record?  In
>

Having tested this in the past by putting Text_IO calls into the stream code, you
appear to get a call for each elementary data object. This will be, of course,
compiler dependent. Granted, its just a memory-to-menory operation rather than an
actual I/O (up to you to do the I/O and you can wait for the buffer to fill.) so the
cost is not extraordinary. But still, all those subprogram calls and memory moves
add up if the structure gets big or you simply do a lot of them. I'd consider it
ill-advised on a hard-realtime project with limited CPU.

>    It seems to me this indicates that Stream_IO may simply be
> inappropriate for such an application.  The only way you can really know
> where the bytes are is via record rep clauses, or by writing your own
> 'Writes to handle everything in your records.  If you depend on the
> compiler, even for Integer'Write, some compiler might some day decide to
> write integers in Roman numeral form, or in some error-correcting code
> expanded form, or whatever, and there goes your app.  My understanding
> is that the only thing you can depend on from the compiler is the
> *sequence* of 'Write calls.

Well, you don't get any absolute guarantees. Look at ARM 13.13.2 {17} and the
surrounding stuff. It seems to imply that if I don't put anything wierd into the
record that I will get out what I expect. In other words, make the record elements
out of things you've defined and controlled representation on such as your own
integers, etc., of known sizes. If I had something like:

type X is record
    Int1   : SInt_32 ;
    Int2  : SInt_16 ;
    Flt1  : Float_96 ;
end record ;

Even if the compiler puts in padding to longword align everything, when I do the
'Write, I should get back what I expect - barring perverse implementations. As you
note, I could create my own 'Write for everything and be certain of what I get.

A perfect solution would be controlled representation of the (tagged) record types
and a fast overlay of a Stream_Element_Array. If you had all the attributes you
needed and could get the representation you wanted, you could very rapidly shove the
bytes down the hose, complete with checksums and byte counts and all the stuff you
want. You'd preserve dispatching and all the high level stuff that made extending
the messages painless, preserved information hiding, let you have all the type
abstractions you wanted and kept the callers from doing any sort of bit-twiddling.
Only problem is, I've tried very hard to make that work and can't get there without
ugly compromises.

MDC
--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================






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

* Re: S'Write and How To Count Bytes
  2000-10-02  0:00         ` tmoran
@ 2000-10-02  0:00           ` Marin David Condic
  2000-10-11  0:00             ` Nick Roberts
  2000-10-02  0:00           ` Ted Dennison
  1 sibling, 1 reply; 29+ messages in thread
From: Marin David Condic @ 2000-10-02  0:00 UTC (permalink / raw)


tmoran@bix.com wrote:

> How about dropping the initial byte count and use an end-of-record
> indicator instead, like LF in Text_IO?

Clearly, one could do that. You could build your whole protocol as if it
were trading lines of text.

The bad news is that for the particular app I'm looking at, I've got an
already defined set of messages. What I am hoping to do is find a nice,
tidy way of using Ada95 to get at that message catalog and build support
tools that connect to the existing system. If the answer is really good,
I might even be able to sell the notion of changing the existing system
and eliminate some really butt-ugly code.

MDC
--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================






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

* Re: S'Write and How To Count Bytes
@ 2000-10-02  0:00 tmoran
  2000-10-03  5:21 ` Marin David Condic
  0 siblings, 1 reply; 29+ messages in thread
From: tmoran @ 2000-10-02  0:00 UTC (permalink / raw)


>... I will get out what I expect.
  type Temperature is new Integer range 60 .. 80;
  for Temperature'size use 8; -- or 7
Is a Temperature'Write going to produce one byte, because that's how
big Temperature is, or 4 bytes, because that's how big Integer is?
  type R is record
    Speed : Long_Integer;
  end record;
  for R use record
    S at 0 range 0 .. 7;
  end record;
Will an R'Write produce one byte for S, or 8 or what?

>A perfect solution would be controlled representation of the (tagged)
>record types and a fast overlay of a Stream_Element_Array.
  I remember this discussion, but not the bottom line.  What's wrong
with
  TAG_SIZE : constant := 4;
  ...
  type This_Buffer is new Buffer with record
    Speed : Integer;
    T : Temperature;
  end record;
  for This_Buffer use record
    Speed at TAG_SIZE range 0 .. 7;
    T at Tag_Size+1 range 0 .. 7;
  end record;
and then overlay a Stream_Element_Array?  (Or a
System.Storage_Elements.Storage_Array?)
  I'd rather trust to TAG_SIZE being 4, or at least a single thing to
change, as I move between compilers, rather than trusting Stream stuff.




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

* Re: S'Write and How To Count Bytes
  2000-09-30  0:00 S'Write and How To Count Bytes Marin David Condic
  2000-10-01  0:00 ` David C. Hoos, Sr.
  2000-10-02  0:00 ` David C. Hoos, Sr.
@ 2000-10-02  6:58 ` tmoran
  2000-10-02  0:00   ` Marin David Condic
  2 siblings, 1 reply; 29+ messages in thread
From: tmoran @ 2000-10-02  6:58 UTC (permalink / raw)


> Is there any good way of determining in advance how many bytes you are
> going to get when converting an object to a stream?
  I don't think I understand.  Why not
  type Buffer_Type is new Root_Stream_Type with record
    Last : Natural := 0;
    Data : Stream_Element_Array(1 .. 1000);
  end record;
  Then each 'write can append its stuff to Data and increment Last
and when they have all finished you have a count and a Stream_Element_Array
to pass to your IO output routine.
-----------------
The experienced programmer knows that work performed after midnight
is likely to be negatively useful.



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

* Re: S'Write and How To Count Bytes
  2000-10-02  0:00     ` Ted Dennison
  2000-10-02  0:00       ` tmoran
@ 2000-10-03  0:00       ` Robert A Duff
  2000-10-06  0:00         ` Randy Brukardt
  1 sibling, 1 reply; 29+ messages in thread
From: Robert A Duff @ 2000-10-03  0:00 UTC (permalink / raw)


Ted Dennison <dennison@telepath.com> writes:

> I'm not sure if implementors are required to make 'Write on unbounded
> strings (or bounded ones for that matter) do anything sensible. I don't
> see anything in the LRM about it, so I'd guess not.

I think there's an AI on this.

- Bob




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

* Re: S'Write and How To Count Bytes
@ 2000-10-03  0:00 Mario Amado Alves
  2000-10-03  0:00 ` Marin David Condic
  0 siblings, 1 reply; 29+ messages in thread
From: Mario Amado Alves @ 2000-10-03  0:00 UTC (permalink / raw)
  To: comp.lang.ada

The "bottom line" was very simple: you may define the representation in
primary storage but not in secondary. This is what the ARM prescribes. I
also would like to see this changed in Ada20XX.

On Mon, 2 Oct 2000 tmoran@bix.com wrote:

> >... I will get out what I expect.
>   type Temperature is new Integer range 60 .. 80;
>   for Temperature'size use 8; -- or 7
> Is a Temperature'Write going to produce one byte, because that's how
> big Temperature is, or 4 bytes, because that's how big Integer is?
>   type R is record
>     Speed : Long_Integer;
>   end record;
>   for R use record
>     S at 0 range 0 .. 7;
>   end record;
> Will an R'Write produce one byte for S, or 8 or what?
> 
> >A perfect solution would be controlled representation of the (tagged)
> >record types and a fast overlay of a Stream_Element_Array.
>   I remember this discussion, but not the bottom line.  What's wrong
> with
>   TAG_SIZE : constant := 4;
>   ...
>   type This_Buffer is new Buffer with record
>     Speed : Integer;
>     T : Temperature;
>   end record;
>   for This_Buffer use record
>     Speed at TAG_SIZE range 0 .. 7;
>     T at Tag_Size+1 range 0 .. 7;
>   end record;
> and then overlay a Stream_Element_Array?  (Or a
> System.Storage_Elements.Storage_Array?)
>   I'd rather trust to TAG_SIZE being 4, or at least a single thing to
> change, as I move between compilers, rather than trusting Stream stuff.
> 

| |,| | | |RuaFranciscoTaborda24RcD 2815-249CharnecaCaparica 351+939354002
|M|A|R|I|O|
|A|M|A|D|O|DepartmentoDeInformaticaFCT/UNL 2825-114 Caparica 351+212958536
|A|L|V|E|S|                                                  fax 212948541
| | | | | |                 maa@di.fct.unl.pt                FCT 212948300






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

* Re: S'Write and How To Count Bytes
  2000-10-03  0:00 Mario Amado Alves
@ 2000-10-03  0:00 ` Marin David Condic
  0 siblings, 0 replies; 29+ messages in thread
From: Marin David Condic @ 2000-10-03  0:00 UTC (permalink / raw)


Mario Amado Alves wrote:

> The "bottom line" was very simple: you may define the representation in
> primary storage but not in secondary. This is what the ARM prescribes. I
> also would like to see this changed in Ada20XX.

Not quite. You can get around the whole mess very simply by creating a
Stream_Element_Array of the appropriate size (minus the tag) and overloaying
it on the object of your record type 'class. With the overlay you can compute
checksums and whatever else you need, then blip the overlay down the wire. It
could all be done in a class-wide operation so that it will handle all
descendent types and avoids all the overhead of moving stuff around in memory
and calling a bunch of small subprograms to convert the elementary objects to
stream elements. You're guaranteed that your representation of data in memory
is what you blipped down the wire because you just overlayed memory with a
byte interpretation of it.

The problem comes in when you try to start slamming representation clauses on
tagged record types. You encounter a) problems with freezing rules. b)
problems with alignments on descendent types, c) compiler bugs, d) no
attributes for determining the size/placement of the tag within the record
(implementation dependence is about all this causes) e) compiler obstinance in
refusing to give you what you want.

IMHO, it would work much nicer and more efficiently than relying on the stream
attributes, but you just can't seem to get it to work all the way through.

MDC
--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================






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

* Re: S'Write and How To Count Bytes
  2000-10-02  0:00 tmoran
@ 2000-10-03  5:21 ` Marin David Condic
  0 siblings, 0 replies; 29+ messages in thread
From: Marin David Condic @ 2000-10-03  5:21 UTC (permalink / raw)


tmoran@bix.com wrote:

> >... I will get out what I expect.
>   type Temperature is new Integer range 60 .. 80;
>   for Temperature'size use 8; -- or 7
> Is a Temperature'Write going to produce one byte, because that's how
> big Temperature is, or 4 bytes, because that's how big Integer is?
>   type R is record
>     Speed : Long_Integer;
>   end record;
>   for R use record
>     S at 0 range 0 .. 7;
>   end record;
> Will an R'Write produce one byte for S, or 8 or what?
>

Didn't say you couldn't create cases that would be tough to make work
consistently. Said that if I used my head and declared my own primitive
types that I would likely get what I wanted. It isn't that often that
someone can't manage to live with "for X'Size use 8"

>
> >A perfect solution would be controlled representation of the (tagged)
> >record types and a fast overlay of a Stream_Element_Array.
>   I remember this discussion, but not the bottom line.  What's wrong
> with
>   TAG_SIZE : constant := 4;
>   ...
>   type This_Buffer is new Buffer with record
>     Speed : Integer;
>     T : Temperature;
>   end record;
>   for This_Buffer use record
>     Speed at TAG_SIZE range 0 .. 7;
>     T at Tag_Size+1 range 0 .. 7;
>   end record;
> and then overlay a Stream_Element_Array?  (Or a
> System.Storage_Elements.Storage_Array?)
>   I'd rather trust to TAG_SIZE being 4, or at least a single thing to
> change, as I move between compilers, rather than trusting Stream stuff.

Oh, you get part way there with that. There's a slew of other problems that
come up and I'd just as soon not start that whole mess again. A lot of it
involves being able to get a representation clause on the record elements
and have the compiler give you what you want instead of what it wants.
Problems with freezing rules. Problems with alignments when you extend the
type, and so on. It really would be the elegant solution, but there doesn't
seem to be a good way to make it happen in such a way that Ada will
guarantee a compiler must do what you want it to do. I got tired of
fighting the compiler, so I put it on the shelf until a later language
revision. :-)

If you're really curious, we could discuss it off-line.

MDC
--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================





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

* Re: S'Write and How To Count Bytes
  2000-10-02  0:00     ` Marin David Condic
@ 2000-10-06  0:00       ` Charles Hixson
  0 siblings, 0 replies; 29+ messages in thread
From: Charles Hixson @ 2000-10-06  0:00 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 2382 bytes --]

In this special case it seems to me that you could write a long 0, divide your
string into fixed length blocks, writing them as you created them, figure the total
block count, go back to the beginning, and write the length there, (and then,
probably, move back to the eof).  Since you are returning an unconstrained string,
you know ahead of time the type that you are returning.

The more general case, where you don't know ahead of time the KIND of value being
returned, is more difficult.  I don't know of any decent way to do this in a
statically bound language, though Lisp, Smalltalk, Python, etc. can handle this by
having a run-time interpreter manage the variable assignments.  And I guess I have
to add Visual Basic into this list, also, out of fairness.

Marin David Condic wrote:

> "Dr. Joachim Schr�er" wrote:
>
> > The 'read, 'write attributes are for constrained types.
> > For unconstrained types (including tagged types/classwide types)
> > there exist the 'input, 'output attributes. Note, that 'input
> > is a function. If you want to overwrite 'input, 'output you just
> > have to overwrite 'read, 'write cause they are used by the former.
>
> I've used the 'Input and 'Output in the process of saving and reloading things
> from a file. It works nicely. However, in this case, I can't have all the dope
> information in the output. See some of the other posts in this thread where I
> explain it in a little more detail. Also, even with the 'Input and 'Output, you
> don't seem to have any means of determining in advance how big a stream of bytes
> you will produce from the operation. I don't see an obvious answer and perhaps
> no good one exists. Probably you would have to convert the data to get the size,
> then convert it again to get the size into the output.
>
> MDC
> --
> ======================================================================
> Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
> Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
> Visit my web site at:  http://www.mcondic.com/
>
>     "Giving money and power to Government is like giving whiskey
>     and car keys to teenage boys."
>
>         --   P. J. O'Rourke
> ======================================================================

-- (c) Charles Hixson
--  Addition of advertisements or hyperlinks to products specifically prohibited


[-- Attachment #2: Card for Charles Hixson --]
[-- Type: text/x-vcard, Size: 145 bytes --]

begin:vcard 
n:Hixson;Charles
x-mozilla-html:FALSE
adr:;;;;;;
version:2.1
email;internet:charleshixson@earthling.net
fn:Charles Hixson
end:vcard

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

* Re: S'Write and How To Count Bytes
  2000-10-03  0:00       ` Robert A Duff
@ 2000-10-06  0:00         ` Randy Brukardt
  2000-10-07  0:11           ` Ted Dennison
  0 siblings, 1 reply; 29+ messages in thread
From: Randy Brukardt @ 2000-10-06  0:00 UTC (permalink / raw)



Robert A Duff wrote in message ...
>Ted Dennison <dennison@telepath.com> writes:
>
>> I'm not sure if implementors are required to make 'Write on unbounded
>> strings (or bounded ones for that matter) do anything sensible. I
don't
>> see anything in the LRM about it, so I'd guess not.
>
>I think there's an AI on this.

Indeed, it is in the Technical Corrigendum. See 13.13.2(36.1/1) in the
revised ARM.

            Randy.

(Wondering about that paragraph number? The ".1" means it is the first
inserted paragraph after paragraph 36; the "/1" means that it is from
revision 1 [i.e. Technical Corrigendum 1])







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

* Re: S'Write and How To Count Bytes
  2000-10-07  0:11           ` Ted Dennison
@ 2000-10-06  0:00             ` Randy Brukardt
  2000-10-07  0:00             ` Marin David Condic
  1 sibling, 0 replies; 29+ messages in thread
From: Randy Brukardt @ 2000-10-06  0:00 UTC (permalink / raw)



Ted Dennison wrote in message <3A061E9A.B8F76112@telepath.com>...
>OK. I went and checked out the nifty new ARM in PDF form (html doesn't
have
>page numbers, presumably due to the formatting limitations of html).
Here's
>what it says:
>
>     {8652/0040} For every subtype S of a language-defined nonlimited
>     specific type T, the output generated by S'Output or S'Write shall
>     be readable by S'Input or S'Read, respectively. This rule applies
>     across partitions if the implementation conforms to the
>     Distributed Systems Annex.
>     36.1/1
>
>Now just reading this cold, I would have figured that "language-defined
>type" meant types defined by the language itself (eg: Integer), rather
than
>defined in a package (eg: System.Address or
>Ada.Strings.Unbounded.Unbounded_String). Thus this passage really
wouldn't
>have anything to say about the workability of Unbounded_String'Write.

Of course, "language-defined" means anything defined by the standard,
and thus includes the contents of any of the language-defined packages.

This rule is just trying to say that these things will work, even if the
native implementation wouldn't work naturally. But that's hard to say in
Reference Manual terms.

                Randy.







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

* Re: S'Write and How To Count Bytes
  2000-10-07  0:11           ` Ted Dennison
  2000-10-06  0:00             ` Randy Brukardt
@ 2000-10-07  0:00             ` Marin David Condic
  2000-10-08  0:00               ` Jean-Pierre Rosen
  1 sibling, 1 reply; 29+ messages in thread
From: Marin David Condic @ 2000-10-07  0:00 UTC (permalink / raw)


Ted Dennison wrote:

> OK. I went and checked out the nifty new ARM in PDF form (html doesn't have
> page numbers, presumably due to the formatting limitations of html). Here's
> what it says:
>
>      {8652/0040} For every subtype S of a language-defined nonlimited
>      specific type T, the output generated by S'Output or S'Write shall
>      be readable by S'Input or S'Read, respectively. This rule applies
>      across partitions if the implementation conforms to the
>      Distributed Systems Annex.
>      36.1/1
>
> Now just reading this cold, I would have figured that "language-defined
> type" meant types defined by the language itself (eg: Integer), rather than
> defined in a package (eg: System.Address or
> Ada.Strings.Unbounded.Unbounded_String). Thus this passage really wouldn't
> have anything to say about the workability of Unbounded_String'Write.
>

That's not the way I would read it if I were the Judge in Language Court. (Idea
for a new T.V. series? Move over Judge Judy!)

If I were the Judge, my legislating from the bench would go like this: "You
guys wrote this ARM. The ARM defines the Ada language. The packages in the
annexes are thus part of the Ada Language. Unbounded_String is a non-limited
type in a language defined package (same as standard). Hence 36.1/1 implies
that when 'Output is called, you can't just dump 32 bits of pointer into the
stream - you've got to implement a 'Output that will write the contents of the
Unbounded_String into the stream such that on 'Input you get back the string.
Your unfunded mandate is to now go off and change your compilers."

But of course, one must now ask what the implications are for 'Read and 'Write?
Would they have to output the contents of the Unbounded_String? (Granted,
you're on your own with respect to the length, but would it be required to
treat the string properly?)

MDC
--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================






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

* Re: S'Write and How To Count Bytes
  2000-10-06  0:00         ` Randy Brukardt
@ 2000-10-07  0:11           ` Ted Dennison
  2000-10-06  0:00             ` Randy Brukardt
  2000-10-07  0:00             ` Marin David Condic
  0 siblings, 2 replies; 29+ messages in thread
From: Ted Dennison @ 2000-10-07  0:11 UTC (permalink / raw)


Randy Brukardt wrote:

> Robert A Duff wrote in message ...
> >Ted Dennison <dennison@telepath.com> writes:
> >
> >> I'm not sure if implementors are required to make 'Write on unbounded
> >> strings (or bounded ones for that matter) do anything sensible. I
> don't
> >> see anything in the LRM about it, so I'd guess not.
> >
> >I think there's an AI on this.
>
> Indeed, it is in the Technical Corrigendum. See 13.13.2(36.1/1) in the
> revised ARM.

OK. I went and checked out the nifty new ARM in PDF form (html doesn't have
page numbers, presumably due to the formatting limitations of html). Here's
what it says:

     {8652/0040} For every subtype S of a language-defined nonlimited
     specific type T, the output generated by S'Output or S'Write shall
     be readable by S'Input or S'Read, respectively. This rule applies
     across partitions if the implementation conforms to the
     Distributed Systems Annex.
     36.1/1

Now just reading this cold, I would have figured that "language-defined
type" meant types defined by the language itself (eg: Integer), rather than
defined in a package (eg: System.Address or
Ada.Strings.Unbounded.Unbounded_String). Thus this passage really wouldn't
have anything to say about the workability of Unbounded_String'Write.

BTW: Good job to everyone involved.

--
T.E.D.

Home - mailto:dennison@telepath.com  Work - mailto:dennison@ssd.fsi.com
WWW  - http://www.telepath.com/dennison/Ted/TED.html  ICQ  - 10545591





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

* Re: S'Write and How To Count Bytes
  2000-10-07  0:00             ` Marin David Condic
@ 2000-10-08  0:00               ` Jean-Pierre Rosen
  2000-10-09  0:00                 ` Randy Brukardt
  2000-10-11  0:00                 ` Marin David Condic
  0 siblings, 2 replies; 29+ messages in thread
From: Jean-Pierre Rosen @ 2000-10-08  0:00 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 766 bytes --]


"Marin David Condic" <mcondic.nospam@acm.org> a �crit dans le message news: 39DF3347.38C82563@acm.org...
> If I were the Judge, my legislating from the bench would go like this: "You
> guys wrote this ARM. The ARM defines the Ada language. The packages in the
> annexes are thus part of the Ada Language.
Well, the cover says: "Ada : the language. The standard libraries". One could argue that everything after the cardboard page belongs
to the standard libraries and not the language...

Picky lawyer hat off: Of course, "language defined types" applies to all types defined in the LRM. :-)

--
---------------------------------------------------------
           J-P. Rosen (Rosen.Adalog@wanadoo.fr)
Visit Adalog's web site at http://pro.wanadoo.fr/adalog






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

* Re: S'Write and How To Count Bytes
  2000-10-08  0:00               ` Jean-Pierre Rosen
@ 2000-10-09  0:00                 ` Randy Brukardt
  2000-10-11  0:00                 ` Marin David Condic
  1 sibling, 0 replies; 29+ messages in thread
From: Randy Brukardt @ 2000-10-09  0:00 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1002 bytes --]

Jean-Pierre Rosen wrote in message <8rt642$g5r$1@wanadoo.fr>...
>
>"Marin David Condic" <mcondic.nospam@acm.org> a �crit dans le message
news: 39DF3347.38C82563@acm.org...
>> If I were the Judge, my legislating from the bench would go like
this: "You
>> guys wrote this ARM. The ARM defines the Ada language. The packages
in the
>> annexes are thus part of the Ada Language.
>Well, the cover says: "Ada : the language. The standard libraries". One
could argue that everything after the cardboard page belongs
>to the standard libraries and not the language...
>
>Picky lawyer hat off: Of course, "language defined types" applies to
all types defined in the LRM. :-)


If you look in the index, you'll find, indexed under "language-defined
types", a list of all of the language defined types. It includes
Unbounded_String and all of the other things declared in those packages.
While the index isn't normative, its pretty clear what the intent of the
language designers was.

            Randy.







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

* Re: S'Write and How To Count Bytes
  2000-10-02  0:00           ` Marin David Condic
@ 2000-10-11  0:00             ` Nick Roberts
  2000-10-11  0:00               ` Marin David Condic
  0 siblings, 1 reply; 29+ messages in thread
From: Nick Roberts @ 2000-10-11  0:00 UTC (permalink / raw)


I would honestly suggest you abandon the use of Ada's streams totally
(except, at least, within the internals of a small package), and define your
own package which formalises the entire message protocol. E.g. (inventing
fictitious commands etc.):


package SCSI is

   type Device_Type is tagged limited private;

   type Device_Status is (Ready, Busy, Spun_Down, Down);

   function Status (Device: in Device_Type) return Device_Status;

   procedure Reset (Device: in out Device_Type);

   ...

   type Block_List is array (Positive range <>) of Block_Number;

   procedure Get_Bad_Sector_Map (
      Device: in out Device_Type;
      Map: out Block_List;
      Last: out Natural);

   ...

   Operation_Not_Supported: exception;

private

   ...

end SCSI;


package body SCSI is

   ...

   type Byte_List is array (Positive range <>) of Unsigned_8;

   procedure Send_Bytes (Device: in out Device_Type; Bytes: in Byte_Array)
is
   begin
      ...
   end;

   procedure Read_Bytes (Device: in out Device_Type; Bytes: out Byte_Array)
is
   begin
      ...
   end;

   ...

   procedure Get_Bad_Sector_Map (
      Device: in out Device_Type;
      Map: out Block_List;
      Last: out Natural) is

      Prelude: Byte_Array(1..1);
      Data: Byte_Array(1..4);

   begin
      Send_Bytes(Device,(1=>16#0A#)); -- fictitious code for 'GETBSMAP'
      Read_Bytes(Device,Prelude);
      -- TBD: check Prelude(1) byte
      Last := Map'First-1;
      loop
         Read_Bytes(Device,Data);
         if Data = (0,0,0,0) then return; end if;
         Last := Last+1;
         Map(Last) := (
            Head_Number(Data(1)),
            Cylinder_Number(Integer(Data(2))*256+Integer(Data(3))),
            Sector_Number(Data(4)));
      end loop;
   end Get_Bad_Sector_Map;

   ...

end SCSI;


You can then allocate memory at exactly the points that make the best sense.
The message protocol itself will determine how efficiently this can be done.
Note how I've illustrated a solution to the unknown length problem similar
to that adopted by Ada.Text_IO.Get_Line on a String. Also note how
SCSI.Device_Type operations can be overridden and extended, neatly
accommodating irregular devices. (Not quite so butt-ugly? ;-)


--
Nick Roberts
http://www.AdaOS.org


----- Original Message -----
From: "Marin David Condic" <mcondic.nospam@acm.org>
Newsgroups: comp.lang.ada
Sent: Monday, October 02, 2000 9:26 PM
Subject: Re: S'Write and How To Count Bytes


> tmoran@bix.com wrote:
>
> > How about dropping the initial byte count and use an end-of-record
> > indicator instead, like LF in Text_IO?
>
> Clearly, one could do that. You could build your whole protocol as if it
> were trading lines of text.
>
> The bad news is that for the particular app I'm looking at, I've got an
> already defined set of messages. What I am hoping to do is find a nice,
> tidy way of using Ada95 to get at that message catalog and build support
> tools that connect to the existing system. If the answer is really good,
> I might even be able to sell the notion of changing the existing system
> and eliminate some really butt-ugly code.







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

* Re: S'Write and How To Count Bytes
  2000-10-08  0:00               ` Jean-Pierre Rosen
  2000-10-09  0:00                 ` Randy Brukardt
@ 2000-10-11  0:00                 ` Marin David Condic
  1 sibling, 0 replies; 29+ messages in thread
From: Marin David Condic @ 2000-10-11  0:00 UTC (permalink / raw)


Jean-Pierre Rosen wrote:

> Well, the cover says: "Ada : the language. The standard libraries". One could argue that everything after the cardboard page belongs
> to the standard libraries and not the language...
>

Ahhhh. But I said "if I were the judge" - so "Overruled!" :-)

>
> Picky lawyer hat off: Of course, "language defined types" applies to all types defined in the LRM. :-)

Well, if you were to exclude Ada.Strings.Unbounded.Unbounded_String as not being a language defined type, on what basis might you say
that Standard.String *was* a language defined type? They are both defined in packages specified by the ARM and they appear in
appendices. The only difference would be names. That's why I figured it would have to apply. Of course this is not necessarily the
thinking that might be applied by a compiler vendor with a non-compliant compiler and no inexpensive fix available. That's when the
lawyers come onto the scene and start bayonetting the wounded. :-)

MDC
--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================






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

* Re: S'Write and How To Count Bytes
  2000-10-11  0:00             ` Nick Roberts
@ 2000-10-11  0:00               ` Marin David Condic
  0 siblings, 0 replies; 29+ messages in thread
From: Marin David Condic @ 2000-10-11  0:00 UTC (permalink / raw)


I'd agree that Streams are not really the best way to accommodate this because
of representation issues. However, I've had representation problems with tagged
records when trying to use byte overlays on them instead of streams.

I don't think your approach addresses quite what I'd like to do. I want a way of
treating the message catalog I've got as if it was a class of related things
with certain kinds of common characteristics. I don't think what you're
proposing below allows me to do that. It looks like you'd just be overlaying
your version of a byte stream on top of some record definitions and calling that
the message system. I could have done that with the standard
Stream_Element_Array and a bunch of plain-vanilla records. However, what I want
is the *elegant*abstraction* of the problem instead of the bit-twiddler answer
that I've always seen resorted to with Ada because of fighting rigorous type
checking or representation problems. If I have to abandon tagged records, I lose
all the nice features of dispatching and class-wide operations. Its not that you
can't build something that will work - you just can't do it with grace and
pinache.

The tagged record and OOP is at least intellectually speaking the "right"
approach because a message catalog is a kind of "class" with common operations
and common data - but with divergent extensions. The collision seems to occur in
that unlike most OO Classes, I've got to a) absolutely control the
representation internally and outside of the box and b) I've got to get around
strict type checking to be able to alternately treat the messages as either a
structured, well-defined record or simply a string of bytes of known length.
This is one problem wherein Ada does not seem to give me the ability to get what
I want out of it and have to resort to some form of compromise.

MDC

Nick Roberts wrote:

> I would honestly suggest you abandon the use of Ada's streams totally
> (except, at least, within the internals of a small package), and define your
> own package which formalises the entire message protocol. E.g. (inventing
> fictitious commands etc.):
>
> package SCSI is
>
>    type Device_Type is tagged limited private;
>
>    type Device_Status is (Ready, Busy, Spun_Down, Down);
>
>    function Status (Device: in Device_Type) return Device_Status;
>
>    procedure Reset (Device: in out Device_Type);
>
>    ...
>
>    type Block_List is array (Positive range <>) of Block_Number;
>
>    procedure Get_Bad_Sector_Map (
>       Device: in out Device_Type;
>       Map: out Block_List;
>       Last: out Natural);
>
>    ...
>
>    Operation_Not_Supported: exception;
>
> private
>
>    ...
>
> end SCSI;
>
> package body SCSI is
>
>    ...
>
>    type Byte_List is array (Positive range <>) of Unsigned_8;
>
>    procedure Send_Bytes (Device: in out Device_Type; Bytes: in Byte_Array)
> is
>    begin
>       ...
>    end;
>
>    procedure Read_Bytes (Device: in out Device_Type; Bytes: out Byte_Array)
> is
>    begin
>       ...
>    end;
>
>    ...
>
>    procedure Get_Bad_Sector_Map (
>       Device: in out Device_Type;
>       Map: out Block_List;
>       Last: out Natural) is
>
>       Prelude: Byte_Array(1..1);
>       Data: Byte_Array(1..4);
>
>    begin
>       Send_Bytes(Device,(1=>16#0A#)); -- fictitious code for 'GETBSMAP'
>       Read_Bytes(Device,Prelude);
>       -- TBD: check Prelude(1) byte
>       Last := Map'First-1;
>       loop
>          Read_Bytes(Device,Data);
>          if Data = (0,0,0,0) then return; end if;
>          Last := Last+1;
>          Map(Last) := (
>             Head_Number(Data(1)),
>             Cylinder_Number(Integer(Data(2))*256+Integer(Data(3))),
>             Sector_Number(Data(4)));
>       end loop;
>    end Get_Bad_Sector_Map;
>
>    ...
>
> end SCSI;
>
> You can then allocate memory at exactly the points that make the best sense.
> The message protocol itself will determine how efficiently this can be done.
> Note how I've illustrated a solution to the unknown length problem similar
> to that adopted by Ada.Text_IO.Get_Line on a String. Also note how
> SCSI.Device_Type operations can be overridden and extended, neatly
> accommodating irregular devices. (Not quite so butt-ugly? ;-)
>
> --
> Nick Roberts
> http://www.AdaOS.org

--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================






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

end of thread, other threads:[~2000-10-11  0:00 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-09-30  0:00 S'Write and How To Count Bytes Marin David Condic
2000-10-01  0:00 ` David C. Hoos, Sr.
2000-10-02  0:00   ` Marin David Condic
2000-10-02  0:00     ` Ted Dennison
2000-10-02  0:00       ` tmoran
2000-10-02  0:00         ` tmoran
2000-10-02  0:00           ` Marin David Condic
2000-10-11  0:00             ` Nick Roberts
2000-10-11  0:00               ` Marin David Condic
2000-10-02  0:00           ` Ted Dennison
2000-10-02  0:00         ` Marin David Condic
2000-10-03  0:00       ` Robert A Duff
2000-10-06  0:00         ` Randy Brukardt
2000-10-07  0:11           ` Ted Dennison
2000-10-06  0:00             ` Randy Brukardt
2000-10-07  0:00             ` Marin David Condic
2000-10-08  0:00               ` Jean-Pierre Rosen
2000-10-09  0:00                 ` Randy Brukardt
2000-10-11  0:00                 ` Marin David Condic
2000-10-02  0:00   ` Dr. Joachim Schr�er
2000-10-02  0:00     ` Marin David Condic
2000-10-06  0:00       ` Charles Hixson
2000-10-02  0:00 ` David C. Hoos, Sr.
2000-10-02  6:58 ` tmoran
2000-10-02  0:00   ` Marin David Condic
  -- strict thread matches above, loose matches on Subject: below --
2000-10-02  0:00 tmoran
2000-10-03  5:21 ` Marin David Condic
2000-10-03  0:00 Mario Amado Alves
2000-10-03  0:00 ` Marin David Condic

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