D - Interface for all Interested:
- Russ Lewis (50/50) Mar 22 2003 This, IMHO, would be a good family of standard interfaces for input
- Matthew Wilson (63/113) Mar 22 2003 It kind of seems nice, but there's always something extra that someone d...
- Jon Allen (30/154) Mar 22 2003 I like it, but I too have a couple suggestions. In C++ I would use char...
- Matthew Wilson (34/203) Mar 22 2003 Cool.
- Jon Allen (23/35) Mar 22 2003 Yeah, but it was kind of obvious, I probably should have noticed it. Th...
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))) ]
Mar 22 2003
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))) ]
Mar 22 2003
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 someonedeemsessential, that "your" interface has omitted and "theirs" has got. Andviceversa. For instance, your InStream deals in char[]. What if the data is binary? Also, expressing the buffering in an interface seems very strange. Onewouldusually 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 dealsinbinary 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 readarraysof 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, andcouldmaybe 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 streamingshouldbe 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,ifanything, 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 thinkwe'dhave something rather fantastic. Even though I am first and foremost a C++ fan, I've hated the iostreamsfora _long_ time, and it would tickle me no end if we could come up with a Dstreams architecture that answered all the iostreams faults withelegance.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))) ]
Mar 22 2003
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 forstreamslike 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 beingpartof the interface. Seek functions would of course be used to replace the start index parameter. You might lose a little speed that way, but Ithinkit'd be worth it. I also think a this(InStream) constructor would be a little moreconsistantthan 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...streamIt kind of seems nice, but there's always something extra that someonedeemsessential, that "your" interface has omitted and "theirs" has got. Andviceversa. For instance, your InStream deals in char[]. What if the data is binary? Also, expressing the buffering in an interface seems very strange. Onewouldusually 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/andsequential-stream interfaces would be the way to go. The interface dealsinbinary stuff only, and different implementing classes can overlay characteristics such as bin-text conversion (cr-lf issues). Perhaps -exchangethis is just off the top of the head - it could look like this interface SequentialInStream { Read . . . // precise signature to be decided, but this would readarraysof 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 datawhat,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, andcouldmaybe 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 streamingshouldbe 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 iniftoanything, 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 thinkwe'dhave something rather fantastic. Even though I am first and foremost a C++ fan, I've hated the iostreamsfora _long_ time, and it would tickle me no end if we could come up with a Dstreams architecture that answered all the iostreams faults withelegance.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 attemptCheckre-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.isretval.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 modelingupa 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 datato 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))) ]
Mar 22 2003
- I did mention bytes in the interface method descriptions, and that would indeed be the recommended interchange type (at least in the interfaces. AsIsaid, the implementing classes would provide suitable overloads)So you did, my bad.- I forgot to show the inheritance relationship of InStream <- SequentialInStream, and OutString <- SequentialOutStreamYeah, 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/orefficiencyof the implementaionWhat 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 :-)
Mar 22 2003