In a previous post, I noted Paul Graham had described Java as an “evolutionary dead-end”. After a lot of thinking about what this means, I've come to the conclusion that it's not really such a bad thing for Java to be. After all, the crocodile is an evolutionary dead-end too, but we don't hold that against it.
Firstly, I must point out that Graham takes pains to state that he is not being directly critical of Java in calling it a dead-end, he is just noting that in one hundred years time we will consider it the end of a branch on the evolutionary tree, rather than a step towards something better. It is partly this sentiment that I take into the essay: that being a branch is not necessarily a bad thing.
Graham's first uses the “evolutionary dead-end” label on COBOL: knowing, of course, that he will get no argument from his audience that COBOL is primitive. In his words, COBOL is Neanderthal1. But we should also remember that there is another evolutionary dead-end related to the Neanderthal, a species we call Homo Sapiens. While one dead-end died out, the other managed to survive another 30,000 years and eventually take over the planet.
So what does it mean to be an evolutionary dead-end? It means, simply, to have evolved to the point at which further evolution is unnecessary. For some species, like the crocodile, this means to be so well adapted to your environment that so long as the environment remains intact, there is no need to change. Unfortunately, such a dead-end is also so well-suited to its environment that if that environment is destroyed, the species quickly becomes extinct. For other species, like Homo Sapiens, this means to have evolved to the point that you remake the environment in your own image, and thus no longer need to adapt.
If Java is an evolutionary dead-end, it is because it has taken a particular path as far as it can be taken in that direction. Any language that descends from Java will look so much like it as to be considered part of the same species, like a new breed of cat. (c.f. C#) None of the attributes that make up Java are unique, so languages that adopt them and branch in new directions will quite correctly mark their parentage from somewhere behind Java in the evolutionary tree of languages.
So what are these features that, combined, make up the path that Java has taken to evolutionary redundancy? Let's start with the good ones:
- Smalltalk-like single-rooted object model and pervasive use of objects.
- Strong, static typing. Dynamically typed languages seem to be winning the mind-share battle, but I've put this under the good list, because it makes Java more suitable for the niche it has found.
- Byte-code compiled, run on a virtual machine. Java was certainly not the first to do this, but it took the concept and made it work on the consumer PC (well, at least after the VM matured and the hardware caught up with its requirements).
- Integrated security-model to allow distinction between trusted and un-trusted code.
- Large, standard library, with many non-essential features considered part of the language, rather than optional add-ons. (an inheritance from the scripting languages, which all do the same thing)
Java's path also includes a number of compromises. These compromises shape the language just as much as its positive features. If you do not understand why it is necessary to make compromises in design if you want to become widely used, I refer you to the classic paper, The Rise Of “Worse is Better”.
- C-like syntax. It's not particularly well-suited to the object-centric view of the world, but it sure is familiar to anyone wanting to learn the language.
- Primitive types. Rather than go the “everything is an object” route, Java compromised and allowed a primitives in. This can be confusing, and requires sundry hacks (object wrappers, or auto-boxing in C#) to overcome, but it is a clasic “Worse is Better” sacrifice of simplicity of interface in favour of simplicity of implementation.
- The lack of real closures makes the language feel a little brain-dead.
- The class library is patchy and inconsistent, especially in the classes that were written early-on, before the naming and structural conventions of the standard library were, well, standard.
The thing to remember about “Worse is Better” is that the essay was written as a tactical paper on how Lisp (both the language and the Lisp machine) was over-shadowed by Unix and C. And in 2003, much to Paul Graham's disappointment I am sure, Unix and C are still dominant. Worse-is-better works. If Java had taken the additional performance hit of closures and not having primitives (on top of the initial performance woes that almost killed it), or if it had broken backwards compatibility to fix the standard library, it might not have been adopted the way it has.
And anyway, while Java's particular combination of features and compromises may, in Graham's eyes, make it an unlikely starting-point for the next wave of language evolution, I can see evolution going on in front of me as we speak, with Java as the platform of choice from which to launch it.
1 In the original version of this essay, I claimed the Neanderthal was an ancestor of Homo Sapiens, something that has actually been proven unlikely.