Friday, April 15, 2011

Dear Java killers,

I love to see all the languages for the JVM popping up on almost a daily basis. Language design is big fun and it's the ultimate thing for a developer to write programs in a language you've built your own. :-)

I especially like the languages which try out new ideas and don't take themselves too seriously, because thinking out of the box is the best you can do in order to push things forward.

However there are also a couple of languages who try hard to attract a certain audience: The Java community. The number of Java developers out there is huge (it had been about 9 million two years ago) so if you could make only a part of this crowd love and use your language it would be a huge  success.
Languages like Groovy, Scala, Clojure, Gosu, Fantom, or lately (but not yet existent) Ceylon and Kotlin more or less try to attract this group. Actually I shouldn't really count Clojure in, because it is so different (I like it though). But all the other languages seem to try to be a better Java for Java developers.

Here are my seven most important Dos and Don'ts you should consider when developing a language for the Java community:

1) Don't make unimportant changes

People are reluctant to change. You should leverage existing knowledge where possible. Changing keywords because you think they sound better might be good for your ego but not for the acceptance of your language. Most languages fall into this trap somehow. The best example is the recently announced Ceylon, which renames all kinds of Java keywords with little reason. For instance the keywords extends and implements are different. In an interview on InfoQ Gavin King explains why he made that decision:
"Java is irregular here. In a class definition, the list of one or more interfaces follows the keyword "implements". In an interface the list of one or more interfaces follows the keyword "extends", which by coincidence may also appear in a class definition where it means something completely different (it is followed by a single class). Ceylon is regular. Lists of types always follow "satisfies". The keyword "extends" is always followed by an expression that instantiates the superclass."
Given that over nine million people are used to it and absolutely understand the semantics, I'd consider this an unfortunate decision.

2) Static Typing


The Java folks are used to top-notch tooling based on static type information. I don't think that errors found by static typing are actually that important, but the tooling you can build on top of this information is. And again it is a matter of the audience you are trying to attract. I wouldn't try to come up with a new statically-typed Ruby, since that doesn't make much sense. I know Mirah and it's not bad. My point is that the Ruby community is not interested in static typing.
Static typing is an important part of the Java culture and the problems it causes can be reduced (see my other advices). Besides that Groovy generally looks a bit overgrown, I'd say the lack of static typing has been a problem for the success of Groovy. Obviously the Groovy folks have understood that and try to fix it with Groovy++.

3) Don't touch generics

Static type systems are complicated. I don't think that more than 1% of all Java developers have really understood generics. All this co- and contra variance, wildcards, raw types, upper and lower bounds and the involved conversion rules are super complicated.
However If asked most Java developers think they know generics and feel quite comfortable with it.
I'm glad that languages like Scala do important work in this area by trying different approaches and having more sophisticated type systems. That's important for the industry but it scares off and there are nine million people out there who feel comfortable with an existing, quite sound type system (aside from very few practically irrelevant problems).

After all generics in Java are rather sound, it's just that the problem they solve is essentially complex.

Also note that reified generics are a bad idea. Type arguments are static type information. They are lying at runtime and the situations where they are helpful are rare. This also breaks interoperability with other JVM languages btw.

4) Use Type Inference

The biggest problem with static typing and generics is that people think that this is the reason why Java code is so cluttered with redundant type signatures. That's not true! It is just a language design decision that one has to be very explicit (or ceremonial) about everything he/she writes down.

A modern statically-typed language should make heavy use of type inference. That is in most situations you give the developer the choice whether to put a type signature or not. Code needs to be concise and readable.

Ceremonial languages like Java don't esteem their users, they think they are stupid and therefore force them to do all kinds of repetitive things. I'm glad the way language or library users are treated has changed in recent years such that developers are given more responsibility for what they do. Only then you can expect quality. The ceremonial style is the biggest problem with Java which urgently needs to be fixed.

5) Care about Tool Support (IDE)

Your language won't be successful within the Java community if it lacks decent tool support. Scala ignored this for quite some time and are now trying to catch up a bit.
My advice is to start working on the IDE while designing the language, because the IDE is an important part of the overall user experience people have with your language. Many syntactical decisions can have a great influence on how the tooling works. A simple example:

In Java when declaring a local variable, Eclipse first proposes you with a type and then afterwards with a name proposal using the simple name of the field's type :

Name proposals in Eclipse
This is simply not possible if you switch the order of type and name like in Scala ( name : Type ), because you first have to type the name.

This is just a simple example, there are other problems hiding in the complexity of a language implementation. Make sure you have an experienced IDE developer in your team and care about the holistic user experience of your language. For Java folks the IDE is an important part of it.

6) Closures

There is no way your language can be successful without closures. Besides the ceremonial verbosity and inflexible syntax of Java the lack of closures is where Java suffers most.
Also for closures type inference and a concise syntax are essential.

7) Get rid of old unused concepts


Removing unnecessary concepts is also a good idea. Java was designed for the C/C++ crowd and was meant to be used in embedded devices and the web. It turned out that it is used quite differently today and most Java developers really don't care about bit shifting, break and continue statements and fall-through switches anymore. Remove them!

APPENDIX

A personal note to the Gavin Kings in this world:

Eclipse Xtext is a language development framework, which not only helps implementing parsers, linkers, compilers and interpreters but also a top-notch Eclipse IDE. You should use it for any kind of language development, because it boosts your productivity and is fun to use.

A general note on Xtext:

Of course there is no mass-market for programming languages. Although Xtext handles them quite well and is used for commercial programming language IDEs, the main focus is to allow people to easily define small, focussed domain-specific languages. The good news is that we have developed a concise, statically typed Java like expression language library supporting everything I mentioned before. And *you* can easily embed it into your DSL! See what you can do with it: