This, IMHO, would be a good family of standard interfaces for input
streams. Thoughts?
BTW, I intentionally designed InStream such that it would be very easy
to overload the array slicing operator....
interface InStream
{
public:
class StreamDataExpired_Error : public Error {};
public:
char[] Get(ulong startIndex,ulong endIndexPlusOne);
// note that the indices here follow the [start..end+1]
convention of array slicing
// Get() may throw StreamDataExpired_Error if you attempt to
re-read an index
// you've read before. Some classes, including the
BufferingInStream interface,
// have the ability to buffer old data and so might
not do that.
// Get() will block until all the data up to endIndex is
ready.
// Get() will return a shorter array if you hit EOF. Check
retval.length to see if this
// happened.
char[] Get(ulong startIndex,ulong endIndexPlusOne,ulong
minEndIndexPlusOne);
// this is like Get(), but will only block to satisfy the
minimum. It will never return
// more than endIndex. Like Get(), it may throw
StreamDataExpired_Error.
};
interface BufferedInStream : InStream
{
// this interface is like InStream, but it buffers all data,
allowing you to view it multiple times.
// This interface is most useful when the stream you're modeling is
a mmap'd file or something
// like that that will be static anyway.
public:
void ExpireDataUpTo(ulong endIndexPlusOne);
// this tells the class that it can discard old buffered data up
to this index. It may ignore you,
// so there is no guarantee that a later call to
Get(<expiredData>) will throw an error (unless
// the class makes that guarantee)
};
--
The Villagers are Online! http://villagersonline.com
.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]

It kind of seems nice, but there's always something extra that someone deems
essential, that "your" interface has omitted and "theirs" has got. And vice
versa.
For instance, your InStream deals in char[]. What if the data is binary?
Also, expressing the buffering in an interface seems very strange. One would
usually imagine that buffering be a characteristic of one concrete
interface-implementer vs another.
I actually think that a rationalised and D-ised version of the COM stream /
sequential-stream interfaces would be the way to go. The interface deals in
binary stuff only, and different implementing classes can overlay
characteristics such as bin-text conversion (cr-lf issues). Perhaps - and
this is just off the top of the head - it could look like this
interface SequentialInStream
{
Read . . . // precise signature to be decided, but this would read arrays
of bytes
}
interface SequentialOutStream
{
Write . . . // precise signature to be decided, but this would write
arrays of bytes
}
interface InStream
{
Seek . . . // tbd
Clone . . . // tbd
other methods tbd
}
interface OutStream
{
Seek . . . // tbd
Clone . . . // tbd
other methods tbd
}
Everything that operates on types could be layered on top of this, in
implementing classes.
I have a moderately elegant C++ template version of object instance
streaming that is syntactically similar to MFC's UpdateData data exchange
thingy, in the sense that the in and out code is written once. The
difference is that everything is resolved at compile time, and it's
exceedingly quick. It layers stuff over a binary stream interface, and could
maybe be converted into D. I'm not yet sufficiently up to speed on D's
templates to say yeah or nay.
The point, however, is that I think the concrete aspects of streaming should
be as generic as poss - binary interface - to reduce feature creep which
limits the number of possible interface-implementing types, and the
object-streaming should be thin as possible - template stuff - to reduce
code size and keep efficiency high. This basically answers the two main
problems with C++'s iostreams.
That all sounds super cool, but of course the real world impacts in what, if
anything, comes between these two layers. This includes character string
streaming, exception-handling, dealing with cr-lf, etc. etc. If this
middle-layer can be sorted such that it is straightforward (in terms of
normal operation and error handling), efficient, extensible by the
programmer without needing much extension in the library, then I think we'd
have something rather fantastic.
Even though I am first and foremost a C++ fan, I've hated the iostreams for
a _long_ time, and it would tickle me no end if we could come up with a
Dstreams architecture that answered all the iostreams faults with elegance.
Trumpeting that on the Boost newsgroup would give D a massive fillip. ;)
Matthew
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3E7C970C.52EE26CD deming-os.org...

This, IMHO, would be a good family of standard interfaces for input
streams. Thoughts?
BTW, I intentionally designed InStream such that it would be very easy
to overload the array slicing operator....
interface InStream
{
public:
class StreamDataExpired_Error : public Error {};
public:
char[] Get(ulong startIndex,ulong endIndexPlusOne);
// note that the indices here follow the [start..end+1]
convention of array slicing
// Get() may throw StreamDataExpired_Error if you attempt to
re-read an index
// you've read before. Some classes, including the
BufferingInStream interface,
// have the ability to buffer old data and so might
not do that.
// Get() will block until all the data up to endIndex is
ready.
// Get() will return a shorter array if you hit EOF. Check
retval.length to see if this
// happened.
char[] Get(ulong startIndex,ulong endIndexPlusOne,ulong
minEndIndexPlusOne);
// this is like Get(), but will only block to satisfy the
minimum. It will never return
// more than endIndex. Like Get(), it may throw
StreamDataExpired_Error.
};
interface BufferedInStream : InStream
{
// this interface is like InStream, but it buffers all data,
allowing you to view it multiple times.
// This interface is most useful when the stream you're modeling is
a mmap'd file or something
// like that that will be static anyway.
public:
void ExpireDataUpTo(ulong endIndexPlusOne);
// this tells the class that it can discard old buffered data up
to this index. It may ignore you,
// so there is no guarantee that a later call to
Get(<expiredData>) will throw an error (unless
// the class makes that guarantee)
};
--
The Villagers are Online! http://villagersonline.com
.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]

I like it, but I too have a couple suggestions. In C++ I would use char*
(for binary or text, or anything else). However, Walter was kind enough to
provide us with a byte[] type which I'm assuming is for those kinds of
ambiguities.
I also think that maybe a buffered interface isn't completely necessary.
As far as seeking and a start index, well they are a great idea for streams
like files and the like, but what about streeaming data from sockets,
keyboards, or anything else that is a little more dynamic? I suggest
leaving off the start index and just using a length and minlength. Seeks
could be implemented in classes where they make sense, instead of being part
of the interface. Seek functions would of course be used to replace the
start index parameter. You might lose a little speed that way, but I think
it'd be worth it.
I also think a this(InStream) constructor would be a little more consistant
than a clone function, but I think either one could be annoying in an
interface.
"Matthew Wilson" <dmd synesis.com.au> wrote in message
news:b5igjc$301c$1 digitaldaemon.com...

It kind of seems nice, but there's always something extra that someone

essential, that "your" interface has omitted and "theirs" has got. And

versa.
For instance, your InStream deals in char[]. What if the data is binary?
Also, expressing the buffering in an interface seems very strange. One

usually imagine that buffering be a characteristic of one concrete
interface-implementer vs another.
I actually think that a rationalised and D-ised version of the COM stream

sequential-stream interfaces would be the way to go. The interface deals

binary stuff only, and different implementing classes can overlay
characteristics such as bin-text conversion (cr-lf issues). Perhaps - and
this is just off the top of the head - it could look like this
interface SequentialInStream
{
Read . . . // precise signature to be decided, but this would read

of bytes
}
interface SequentialOutStream
{
Write . . . // precise signature to be decided, but this would write
arrays of bytes
}
interface InStream
{
Seek . . . // tbd
Clone . . . // tbd
other methods tbd
}
interface OutStream
{
Seek . . . // tbd
Clone . . . // tbd
other methods tbd
}
Everything that operates on types could be layered on top of this, in
implementing classes.
I have a moderately elegant C++ template version of object instance
streaming that is syntactically similar to MFC's UpdateData data exchange
thingy, in the sense that the in and out code is written once. The
difference is that everything is resolved at compile time, and it's
exceedingly quick. It layers stuff over a binary stream interface, and

maybe be converted into D. I'm not yet sufficiently up to speed on D's
templates to say yeah or nay.
The point, however, is that I think the concrete aspects of streaming

be as generic as poss - binary interface - to reduce feature creep which
limits the number of possible interface-implementing types, and the
object-streaming should be thin as possible - template stuff - to reduce
code size and keep efficiency high. This basically answers the two main
problems with C++'s iostreams.
That all sounds super cool, but of course the real world impacts in what,

anything, comes between these two layers. This includes character string
streaming, exception-handling, dealing with cr-lf, etc. etc. If this
middle-layer can be sorted such that it is straightforward (in terms of
normal operation and error handling), efficient, extensible by the
programmer without needing much extension in the library, then I think

have something rather fantastic.
Even though I am first and foremost a C++ fan, I've hated the iostreams

a _long_ time, and it would tickle me no end if we could come up with a
Dstreams architecture that answered all the iostreams faults with

Trumpeting that on the Boost newsgroup would give D a massive fillip. ;)
Matthew
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3E7C970C.52EE26CD deming-os.org...

This, IMHO, would be a good family of standard interfaces for input
streams. Thoughts?
BTW, I intentionally designed InStream such that it would be very easy
to overload the array slicing operator....
interface InStream
{
public:
class StreamDataExpired_Error : public Error {};
public:
char[] Get(ulong startIndex,ulong endIndexPlusOne);
// note that the indices here follow the [start..end+1]
convention of array slicing
// Get() may throw StreamDataExpired_Error if you attempt to
re-read an index
// you've read before. Some classes, including the
BufferingInStream interface,
// have the ability to buffer old data and so might
not do that.
// Get() will block until all the data up to endIndex is
ready.
// Get() will return a shorter array if you hit EOF. Check
retval.length to see if this
// happened.
char[] Get(ulong startIndex,ulong endIndexPlusOne,ulong
minEndIndexPlusOne);
// this is like Get(), but will only block to satisfy the
minimum. It will never return
// more than endIndex. Like Get(), it may throw
StreamDataExpired_Error.
};
interface BufferedInStream : InStream
{
// this interface is like InStream, but it buffers all data,
allowing you to view it multiple times.
// This interface is most useful when the stream you're modeling is
a mmap'd file or something
// like that that will be static anyway.
public:
void ExpireDataUpTo(ulong endIndexPlusOne);
// this tells the class that it can discard old buffered data up
to this index. It may ignore you,
// so there is no guarantee that a later call to
Get(<expiredData>) will throw an error (unless
// the class makes that guarantee)
};
--
The Villagers are Online! http://villagersonline.com
.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]

Cool.
A couple of clarifications:
- I did mention bytes in the interface method descriptions, and that would
indeed be the recommended interchange type (at least in the interfaces. As I
said, the implementing classes would provide suitable overloads)
- I forgot to show the inheritance relationship of InStream <-
SequentialInStream, and OutString <- SequentialOutStream
I don't get your point about seeking, indexes, sockets, etc. The whole point
of the sequential streams being the upper parts of the In/Out hierarchies is
so that non-indexible and non-rewindable streams would be catered for.
Indeed, it is more than likely that these would be the most often used
interfaces, even on entities that could support the derived interfaces.
I may not understand D well enough, but as I understand it, interfaces
cannot have ctors, so I don't think your this(InStream) thing will work.
Plus, by requiring the client code to explicitly create the cloned stream
instance, we would unnecessarily constrain the flexibility and/or efficiency
of the implementaion (e.g. clones of a certain implementing may be cached).
I also don't see why a Clone method could be confusing. It is a well-used,
and very useful, idiom: it allows one to "remember" a position and then pass
the interface off to another section of code to use, and vice versa.
"Jon Allen" <jallen minotstateu.edu> wrote in message
news:b5ivod$8ok$1 digitaldaemon.com...

I like it, but I too have a couple suggestions. In C++ I would use char*
(for binary or text, or anything else). However, Walter was kind enough to
provide us with a byte[] type which I'm assuming is for those kinds of
ambiguities.
I also think that maybe a buffered interface isn't completely necessary.
As far as seeking and a start index, well they are a great idea for

like files and the like, but what about streeaming data from sockets,
keyboards, or anything else that is a little more dynamic? I suggest
leaving off the start index and just using a length and minlength. Seeks
could be implemented in classes where they make sense, instead of being

of the interface. Seek functions would of course be used to replace the
start index parameter. You might lose a little speed that way, but I

it'd be worth it.
I also think a this(InStream) constructor would be a little more

than a clone function, but I think either one could be annoying in an
interface.
"Matthew Wilson" <dmd synesis.com.au> wrote in message
news:b5igjc$301c$1 digitaldaemon.com...

It kind of seems nice, but there's always something extra that someone

essential, that "your" interface has omitted and "theirs" has got. And

versa.
For instance, your InStream deals in char[]. What if the data is binary?
Also, expressing the buffering in an interface seems very strange. One

usually imagine that buffering be a characteristic of one concrete
interface-implementer vs another.
I actually think that a rationalised and D-ised version of the COM

/

sequential-stream interfaces would be the way to go. The interface deals

thingy, in the sense that the in and out code is written once. The
difference is that everything is resolved at compile time, and it's
exceedingly quick. It layers stuff over a binary stream interface, and

maybe be converted into D. I'm not yet sufficiently up to speed on D's
templates to say yeah or nay.
The point, however, is that I think the concrete aspects of streaming

be as generic as poss - binary interface - to reduce feature creep which
limits the number of possible interface-implementing types, and the
object-streaming should be thin as possible - template stuff - to reduce
code size and keep efficiency high. This basically answers the two main
problems with C++'s iostreams.
That all sounds super cool, but of course the real world impacts in

if

anything, comes between these two layers. This includes character string
streaming, exception-handling, dealing with cr-lf, etc. etc. If this
middle-layer can be sorted such that it is straightforward (in terms of
normal operation and error handling), efficient, extensible by the
programmer without needing much extension in the library, then I think

have something rather fantastic.
Even though I am first and foremost a C++ fan, I've hated the iostreams

a _long_ time, and it would tickle me no end if we could come up with a
Dstreams architecture that answered all the iostreams faults with

Trumpeting that on the Boost newsgroup would give D a massive fillip. ;)
Matthew
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3E7C970C.52EE26CD deming-os.org...

This, IMHO, would be a good family of standard interfaces for input
streams. Thoughts?
BTW, I intentionally designed InStream such that it would be very easy
to overload the array slicing operator....
interface InStream
{
public:
class StreamDataExpired_Error : public Error {};
public:
char[] Get(ulong startIndex,ulong endIndexPlusOne);
// note that the indices here follow the [start..end+1]
convention of array slicing
// Get() may throw StreamDataExpired_Error if you attempt

re-read an index
// you've read before. Some classes, including the
BufferingInStream interface,
// have the ability to buffer old data and so might
not do that.
// Get() will block until all the data up to endIndex is
ready.
// Get() will return a shorter array if you hit EOF.

retval.length to see if this
// happened.
char[] Get(ulong startIndex,ulong endIndexPlusOne,ulong
minEndIndexPlusOne);
// this is like Get(), but will only block to satisfy the
minimum. It will never return
// more than endIndex. Like Get(), it may throw
StreamDataExpired_Error.
};
interface BufferedInStream : InStream
{
// this interface is like InStream, but it buffers all data,
allowing you to view it multiple times.
// This interface is most useful when the stream you're modeling

a mmap'd file or something
// like that that will be static anyway.
public:
void ExpireDataUpTo(ulong endIndexPlusOne);
// this tells the class that it can discard old buffered data

to this index. It may ignore you,
// so there is no guarantee that a later call to
Get(<expiredData>) will throw an error (unless
// the class makes that guarantee)
};
--
The Villagers are Online! http://villagersonline.com
.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]

- I did mention bytes in the interface method descriptions, and that would
indeed be the recommended interchange type (at least in the interfaces. As

said, the implementing classes would provide suitable overloads)

So you did, my bad.

- I forgot to show the inheritance relationship of InStream <-
SequentialInStream, and OutString <- SequentialOutStream

Yeah, but it was kind of obvious, I probably should have noticed it. That's
what I get for "skimming" pseudo-code :-)

I don't get your point about seeking, indexes, sockets, etc.

My point is basically that I don't like having a start index as part of a
top level interface like Burton had it, but rather:
interface SequentialInStream{byte[] read(int length);}
interface InStream:SequentialInStream{void seek(int pos);}
I think that is what you are saying anyhow. Right?

I may not understand D well enough, but as I understand it, interfaces
cannot have ctors, so I don't think your this(InStream) thing will work.

You are right, I tried it and it doesn't work. This is annoying to me,
anyone else?

I also don't see why a Clone method could be confusing.

I don't think it would be confusing. My point is that the clone function is
basically just constructing a new instance of the class anyhow, so it's just
a special case to remember.

Plus, by requiring the client code to explicitly create the cloned stream
instance, we would unnecessarily constrain the flexibility and/or

of the implementaion

What can you do with this:
blah blah=oldblab.clone();
that you can't do with this:
blah blab=new blah(oldblab);
just as easily and efficiently? Either way the client still has to
explicitly create the instance.
Of course it my arguments against a clone function are easily overcome by
the fact that my alternative doesn't actually work. grrr :-)