Suggestions for std.stream (esp. for 64bit)

Daniel Gibson metalcaedes at gmail.com
Wed Oct 6 09:23:12 PDT 2010


Daniel Gibson schrieb:
> I'm using some of std.stream's classes (and also SocketStream) in a 
> project of mine (it currently uses D1 but std.Stream hasn't changed much 
> so all this is valid for D2 as well).
> std.stream is mostly what I expect from classes for Streams (having 
> experience with Java's equivalents). However there are a few things that 
> I think could/should be improved.
> 
> 1. (important for 64bit D): write(char[]) and read(char[]) are too 
> platform specific.
> These methods (and the wchar counterparts) write (or read) "a string, 
> together with its length". This is fine (even though I would rather 
> expect writeString/readString to do this magic, but nevermind), *but* 
> the length is written as a size_t - making it heavily platform dependant.
> This means that you can't use write(char[]) to write into a file on a 
> x86 system and later read that file on an amd64 system. Also consider 
> SocketStream.. you can't use SocketStream.write(char[]) to communicate 
> between a x86 and an amd64 box (when an 64bit executable is used an the 
> latter).
> This could easily be fixed by using uint or ulong instead of size_t on 
> all platforms. (uint is probably ok, Java even uses short in a similar 
> method (java.io.DataOutput.writeUTF() - never use this, it's no real 
> UTF-8)).
> 
> Unfortunately the libphobos of GDC (that already supports 64bit targets) 
> has been using size_t for ages, so in D1 it should maybe stay like that 
> to avoid breaking compatibility (on the other hand probably no GDC user 
> who thinks at least a bit cross-platform uses write(char[]) anyway - in 
> that case just use uint so it's compatible with existing 32bit binaries 
> from DMD).
> But at least for D2/phobos2 that should be changed.
> 
> 2. The documentation says for write(): "Outside of byte, ubyte, and 
> char, the format is implementation-specific and should only be used in 
> conjunction with read. Throw WriteException on error."
> So how do I write files for other programs to read? How do I communicate 
> with servers/clients not written in D with a SocketStream?
> Fortunately the documentation exaggerates. Apart from write(char[]) and 
> write(wchar[]) the claim is not true.
> The simple types are platform specific, not specific to D/std.stream - 
> so a program written in C (or any other language) is probably able to 
> read that data (if it supports the type - may be tricky with real and 
> maybe the imaginary types).
> And by using the EndianStream, most of the types probably can be read by 
> other platforms (again, real and the imaginary types might cause 
> trouble.. and maybe floating point types in general, if the other 
> platform doesn't support IEEE 754 floats - but integer types are 
> definitely safe).
> 
> This is bad, because if someone wants to use SocketStream he's confused 
> by that statement until he looks at the source to find out that it's not 
> so implementation specific after all.
> So please document how exactly write( (w)char[]) encodes the length and 
> also make clear that write( <basic type> ) does no strange voodoo, but 
> just dumps the bytes of the value (in platform specific big/little 
> endian order).
> 
> 3. InputStream's read( <type> val) often is inconvenient.
> If you want to read an int (or any other basic type) from an InputStream 
> s you have to do:
>   int foo; s.read(foo);
> This doesn't look soo horrible.. but maybe you want to pass that value 
> directly to a function?
>   int foo; s.read(foo); bar(foo);
> This is inconvenient. Java has something like Stream.readInt(), so you 
> can write
>   bar( s.readInt() );
> That's much shorter and you don't need to invent a name for that value 
> you only want to use once anyway.
> For D I'd suggest a templated method for that:
>   T read(T)() { T ret; readExact(&ret, ret.sizeof); return ret; }
> So you could write
>   int foo = s.read!int; // instead of int foo; s.read(foo);
> or even
>   auto foo = s.read!int;
> and
>   bar( s.read!int ); // instead of "int foo; s.read(foo); bar(foo);"
> (The implementation should probably make sure T is a basic type or maybe 
> a struct, but no array or Object or pointer. Also special cases for 
> char[] and wchar[] might be needed for consistency.)
> 
> 4. Minor inconsistencies:
> In InputStream there is a read(ubyte[]) method, but no 
> readExact(ubyte[]) method.
> I'd suggest adding
>   void readExact(ubyte[] buf) { readExact(buf.ptr, buf.length); }
> and, for convenience
>   ubyte[] readExact(size_t len) {
>     ubyte[] ret = new ubyte[len];
>     readExact(ret.ptr, len);
>     return ret;
>   }
> 
> Also there is a write(ubyte[]) method in OutputStream, but no 
> writeExact(ubyte[]) method, so I'd suggest adding
>   void writeExact(ubyte[] buf) { // maybe "const(ubyte[]) buf" for D2
>     writeExact(buf.ptr, buf.length);
>   }
> 
> 
> 
> All code above is untested and thus to be considered pseudo-code ;-)
> 
> Cheers,
> - Daniel

I filed two bug reports on this:
http://d.puremagic.com/issues/show_bug.cgi?id=5001 for the 64bit 
write(char[]) issue
http://d.puremagic.com/issues/show_bug.cgi?id=5002 for the other 
suggestions.


More information about the Digitalmars-d mailing list