13 February 2008

Two gripes about the Java library, and what they say about language design

So, as far as programming languages go, Java is far from the worst.
However, it's nowhere near the best either. Here are a few grips
which popped into mind right now:

(1) java.io.OutputStream is a class. It should instead be an
interface. Why? Because there are a trillion things which act like
an OutputStream, but which don't share any code with it.

So why does java make a distinction between interfaces and classes?
Because multiple inheritance is hard to implement--you don't just need
a virtual table for each of the methods, but also for each of the
fields. Yech.

The ultimate failing here is that Java lacks mixins. Class
java.io.OutputStream is a class because they want to be able to
implement OutputStream.write(byte[], int, int) in terms of
OutputStream.write(byte), or maybe the other way around. A minor
savings at a great cost.

Interfaces are not allowed to have any code. A mixin is an interface
that's allowed to have code, but no fields. But mixins are still
really easy to implement, so there's no reason to not include them.

(2) java.lang.StringBuffer does not implement java.io.OutputStream.
Why not? As far as I can tell, it is a sink into which I dump bytes,
chars, strings, etc. But no, I have to wrap it in a trillion adaptor
classes instead.

Sure, it implements java.lang.Appendable, but who ever heard of
Appendable? Despite my casual language, I more specifically mean: who
ever wrote something that requires an Appendable? Everyone wrote
something that requires an OutputStream, and an OutputStream is not an
Appendable!

1 comment:

Nick Johnson said...

StringBufferOutputStream.java:

import java.io.*;
import java.lang.*;

/**
* An output stream which puts its output to a stringbuffer
*/
class StringBufferOutputStream extends OutputStream {

StringBuffer sink;

ByteCounterOutputStream(StringBuffer s) {
super();
sink = s;
}

public void write(byte[] byteArray, int offset, int count) {
sink.append( new String(byteArray,offset,count));
}
}