Friday, September 12, 2003

Why Java sucks more than C++ does

No, this isn't a language rant; I just wanted a catchy title.

I've been writing various containers, adaptors, iterators and algorithms for Java and I'm growing tired of some of the obstacles. The Collections Framework gets a solid B but no higher. This is because while Java is an excellent language for object-oriented programming, it is very poor for generic programming. In particular, Java lacks support for generics and mixins and the generics proposals for Java 1.5 only partly addresses these deficiencies. (See the NextGen project for something more in the right direction.) In a very fundamental way, Java is a single paradigm programming language. In contrast, C++ strives to be a multi-paradigm language. A quick comparison:

  C++ Java
Structured Excellent Good
Object-oriented Excellent Excellent
Generic Good None
Funtional Fair None

What does all this mean?

Structured programming is ubquitous now days, and C++ and Java are both intellectual heirs to ALGOL and other early structured-programming languages. They have syntax-driven control structures such as if ... else and while to remove the need for the much dreaded goto. But I fault Java for lacking goto for certain kinds of effecient exception handling within a method and for making Duff's device illegal. How could they?

Object-oriented programming we all know and love. The problem even here is that Java requires OOP even when you don't need it. But it does have OOP in spades.

Generic programming is parameterization by type permitting strong typing of untyped language constructs. The classic example is List which is a list container of Foo objects. C++'s weakness is it's over-strong type system which prevents true virtual constructors and the like. Java simply lacks the facility all together.

Functional programming is programing to the Lambda Calculus. C++ supports this with functors, objects supporting function call syntax, but still lacks truly first-class function objects (although the proposed <functional> is closer than before).

On the gripping hand, there is no VM for C++ to run my compiled object code everywhere without recompilation, and Java's package system is very excellent; namespaces are a compiler symbol table hack, not a fully integrated run-time feature.

As you can see from this list, writing generic containers, adaptors, iterators and algorithms is tricky with Java. The lack of good generics really blows. A particular example: I'm been writing and rewriting a Stack interface. Because of Java's single-inheritance, I am unable to make a really good adaptor with it. How do you tack it onto an existing List implementation in a really smart way? If your implementation is a RandomAccess container (read ArrayList), then you want to push objects onto the end of the list since adding to the front is so expensive; if it is not a RandomAccess container (read LinkedList) then you want to push objects onto the front of the list since accessing the last element is so expensive. In C++ I can handle this easily with template specialization and mixins (multiple inheritance), but these are foreign to Java.

Perhaps in Java 1.6 things will be easier.

No comments: