I hate java quite a lot. Java is both nice and stupid and horribly broken. Java is nice because all the features it has that lisp has, such as object-orientation, byte compilation, and garbage collection, but broken because it has a stupid type system.

  1. Interfaces don't allow specification of static methods or constructors
  2. It is statically typed
  3. It doesn't allow union types

1) Interfaces don't allow specification of static methods or constructors

This is bad because when I want to use reflective features to instantiate an object, I can't use the compiler to guarantee that all my objects have the same interface for construction. Also, specifying static methods allows us to get "extra introspection", so the class can tell us stuff about itself, but that's just froth. The real reason I want it is for when I'm dynamically deciding what class to instantiate.

2) It is statically typed

Static typing adds nothing to object-oriented languages - they carry type information around in objects, so there is no speed or space advantage. On the other hand, it does make things considerably less convenient. Imagine that (for some crazy reason) you're storing things in a Collection, and everything comes back out as Objects. This is bad because you were mainly storing bytes anyway, and you had to allocate a load of wrapper objects. The other situation where static typing is bad is...

2.5) It doesn't allow union types

When declaring variable types (which I don't want to do, except when it's really necessary, as when catching exceptions, but it's a taste thing), you can't declare the variable to be of a union type: (or TooFatException TooThinException). If the actions are always the same, and the only methods you want to invoke on the exception are those of an exception, you can't use a union, you have to have 2 catch blocks, doubling the code you have to maintain, and when you're developing code like this, you always find bugs, and you have to fix them twice. Introduce the errors! Introduce the errors!

In case you think inheritance helps here, consider the case where I am catching exceptions whose types I didn't create, which is the usual case. Here inheritance will not help me, because I do not define the inheritance hierarchy. Also, what if there is a TooUglyException that should be handled differently from the other TooFooExceptions?. You could do:

catch(TooFooException x)
   if(x instanceof TooUglyException){throw (TooUglyException)x;}
The problem with this is that I must know about the entire TooFooException hierarchy, and if a new class is added, this code has to change. Also, if there are many classes in the hierarchy, I must have many if-statements to find the correct type to cast the exception to, or lose type information by just throwing TooFooExceptions. Both are bad.

Many if-statements make the code hard to read, and navigate, and as it's going to need maintaining every time a new exception is added, this is is bad. Losing type information is bad because users of the code are either going to jave to catch TooFooExceptions, and make no ditinction between them, or use if-statements to use the exceptions sensibly. This forces users of your code to adopt your programming style, which is bad.

There is also the objection that a union type is fundamentally different from the way java does things at present, because you can tell from a class' declaration all possible types that it is a subtype of. This is true. However, what I am arguing for is not union types, but union tyoe declarations, so that a variable that is of type (or Foo Bar) does not refer to a varibale that is in some way a combination of Foo and Bar, but rather that it can hold EITHER a Foo, or a Bar. Also, because I am against static typing, as mentioned above, when throwing a union type, it will be thrown as the right type (ie the type that the object is) rather than as the union type of the variable. There is also the rather more meaty objection that you still have to deal with type incompatibilities. Java already has reflection, so if you're careful, you can use that to check that the method you want to invoke exists (Although while I'm wishing for a better type system, we need a new reflection syntax. The current syntax can only be described as god-awful). You could just invoke the operation, and deal with the exception that arised if you invoked a non-existent method. Or, more sensibly, you could simply only invoke methods that you know exist on all types in the declaration, which, as far as I can see, is the only time you'd want to use a union declaration.