www.digitalmars.com         C & C++   DMDScript  

D - Streaming in D

I thought a bit about how to do streaming in D. As you can't write global
operators, my first thought was using traits. This wouldn't be a problem in D,
as it supports templates and specialization. But I haven't testet D's abilitys
concerning that. Is it possible to specialize templates in multiple modules?
But than I rememberd, that Object has a methode toString(), that could be used.
So D's streams could accept an Object. But what if you haven't implemented
toString()? Than you wouldn't get an error, but "Object" would be written into
the stream. This is a stupid behavior. The implementation of toString should do
something like

assert(0);

In my opinion all methodes of Object should be implemented like this.
Perhaps a interface like ConvertableToString might be an option. So streams
would accept objects that implement this interface. This interface only provides
the methode toString(). So you know whether a object is realy convertable to
string or not. Well, it seems a bit strange as Object already has a toString().
But as it can be used without warnings or errors this seems to be the only safe
way.


Back to the traits idea. It might look like the folowing (not tested):

// in modul template_meta (should become part of std)

class YesType {}
class NoType {}

template IsInternalType (T) { typedef NoType YesNo; }

template IsInternalType (T : byte)   { typedef YesType YesNo; }
template IsInternalType (T : ubyte)  { typedef YesType YesNo; }
template IsInternalType (T : short)  { typedef YesType YesNo; }
template IsInternalType (T : ushort) { typedef YesType YesNo; }
template IsInternalType (T : int)    { typedef YesType YesNo; }
template IsInternalType (T : uint)   { typedef YesType YesNo; }
template IsInternalType (T : long)   { typedef YesType YesNo; }
template IsInternalType (T : ulong)  { typedef YesType YesNo; }
template IsInternalType (T : float)  { typedef YesType YesNo; }
template IsInternalType (T : double) { typedef YesType YesNo; }
template IsInternalType (T : real)   { typedef YesType YesNo; }
template IsInternalType (T : ireal)  { typedef YesType YesNo; }
template IsInternalType (T : creal)  { typedef YesType YesNo; }
template IsInternalType (T : char)   { typedef YesType YesNo; }
template IsInternalType (T : wchar)  { typedef YesType YesNo; }
// Strings count as special internal type
template IsInternalType (T : char[]) { typedef YesType YesNo; } 
template IsInternalType (T : wchar[]){ typedef YesType YesNo; }


// In modul stream_traits

import std.template_meta;

template StreamWriteTrait (T) {
void writeToStream (T object, Stream stream)
in {
assert (stream.writable());
}
body {
stream.write (object.toString());
}



template StreamReadTraitImplementation (T, U : YesType) {
void readFromStream (out T object, Stream stream)
body {
stream.read (object);
}
}


template StreamReadTraitImplementation (T, U : NoType) {
void readFromStream (out T object, Stream stream)
body {
char [] temp;
stream.read (temp);
object = new T (temp);
}
}


template StreamReadTrait (T) {
instance IsInternalType (T) isInternal;
instance StreamReadTraitImplementation (T, isInternal.YesNo) implementation;

void readFromStream (out T object, Stream stream)
in {
assert (stream.readable());
}
body {
implementation.readFromStream (object, stream);
}
}


// You have to specialize StreamReadTrait and StreamWriteTrait for your own
types
// if the default version doesn't fit.
Nov 20 2003