Saturday, April 16, 2005

Multiplicity

Finally, someone in the C++ community that realises how far the language has fallen behind becuase its missing a decent library.

"I'm going to speculate now, because I haven't been watching Java and I've just got my feet a little bit wet in .NET. But I would say that while the C++ community was focusing on templates, the STL, and exceptions—oddly enough the three are wrapped up together pretty closely—what they were not doing was component-based development. For example, there is no huge collection of class libraries for C++. The standard library for C++ is pretty impoverished. In the meantime, the rest of the world was busy creating huge class libraries that let you write all kinds of really neat applications without having to write very much code. Certainly Java is famous for its libraries. .NET has a huge number of libraries."
- Scott Meyers

Abstract Base Classes

I was reading the above article becuase ive just been using multiple inheritance in my own library. The design forced me to use it and i wanted to validate some of my rational. Multiple inheritance allowed me to connect up the notion of streams with that of lower level IO like files and sockets. So whilst i have a File class and a Socket class i also have a Stream class and an associated FileStream and SocketStream, each of which derive multiply from the base class of that type and implement the Stream interface. The interesting part is that Stream implements two other interfaces, Reader and Writer. File and Socket also implement Reader and Writer which define some standard contracts for reading and writing bytes.


class Reader
{
...
virtual int Read(char * data, int size)=0;
virtual int Read(Writer & writer, int amount=0);
...
};

class Writer
{
...
virtual int Write(char * data, int size)=0;
virtual int Write(Reader & reader, int amount=0);
...
};


This is a very useful notion, it lets me have Stream's which i can use for efficient progressive reading, writing, and seeking, but i can also use these streams interact with their more primitive classes. For instance, to read from a SocketStream directly into a File i can do this:


SocketAddress socketAddress("www.google.com",80);
SocketStream socketStream;
socketStream.Connect(socketAddress);
socketStream.Write("GET / HTTP/1.0\r\n\r\n");

File file("/tmp/google.html");
file.Write(socketStream);


And now i have a local copy of the html page. It works becuase the Reader and Writer interfaces allow direct connections to one another. This provides interoperability between streams and other forms of IO when i just want to do a simple redirection. But i can still harness all the pipelining capability of streams when i need it.

The inheritance heirarchy of the FileStream class looks like this:

FileStream
[
File
[
Filesystem
[...]
Reader
Writer
]
Stream
[
Reader
Writer
]
]


Of course the FileStream can do everything that a File can do, but it also blends with it Stream semantics. Multiple inheritance allows the common interfaces to be merged and the simple composition of two distinct usage patterns into a single class.

Its nice when an intuitive design just jumps out at you, its a rare example of a truly useful piece of multiple inheritance.