Thursday, 26 February 2015

Android: Forking Java by Mistake

Java has been forked, and Google is the reason. Allow me to explain.

Back in the days of Cupcake and Donut, when Android was new and shiny, one of the things that made it attractive to developers was that they could use a language they were familiar with on this new platform. That language was Java, and of course the version used was a modern one. The most recent version of Java at the time was version 6.

Of course, Java moved forward. 6 was end-of-lifed in February, 2013, and version 7 is now the oldest version supported by Oracle. Java 7's end of public updates is looming, coming as it does in April 2015. Java 7 introduced a bunch of new APIs and useful features. Some of these, such as better generics inference, are syntactic sugar and provided by the compiler, but some of these (notably "try-with-resources") need support from the runtime. That support only appeared in Android KitKat.

Versions of Android before KitKat still account for just under 60% of the market according to Google's own dashboards. That means that someone who wants to target as much of the Android market as possible has a choice to make: use Java 7's fancy new features, or stick with Java 6. Android's toolchain supports taking Java 7 bytecode, so all the syntactic sugar provided by the compiler is available, but you can't use the new features. Things are only going to get worse as Java 8 gets wider adoption --- features such as lambdas look like they're going to be widely used, especially as the functional paradigm becomes more widespread.

Java has a vast collection of OSS and commercial libraries out there for Doing Useful Things. If an app chooses to target Java 6, every library it depends on must also make that same choice.

This means that the Java market is now forking. Server-side Java is forging ahead, and the libraries that it uses are increasingly starting to use modern Java features, unless enough of their users ask for Android compatibility.

So, what can Google do to keep the world moving forward? How can developers use a more modern Java whilst still being usable by the largest part of the Android market.

The simplest thing would be to release a shim that developers can optionally load on pre-KitKat Android. Oracle's lawsuit about API infringement may make this a deeply undesirable route for them to follow.

Alternatively, individual developers can pack any required classes and APIs into their own apps. That seems like an error-prone way of doing things --- it's way too easy to accidentally use these new APIs by accident, and someone who only tests on a recent device will miss the versioning problem.

Finally, I guess some benevolent third party could create the required shim, but getting widespread usage may be difficult, and it's hardly ideal.

Once Java 8 features come into widespread use (or the use of invokedynamic gets more traction), the situation won't be so simple. I seriously hope the big brains running Android are getting ahead of this problem --- we'll need platform support to solve this problem properly, and we'll need it soon.

Until that support arrives, Java has been forked, with two family trees each with Java 6 as their common ancestor.