Friday, August 26, 2011

Is Scala worthy of your trust?

The Scala language offers significant improvements over the Java language with traits, higher order functions and type inference among other powerful features. At the same time, Scala still allows for seamless import and use of existing classes written in Java. You can migrate to Scala piecemeal, for example in your test classes at first and then migrate larger and larger chunks of code.

However, there is one aspect to the Scala language which I find deeply annoying. Scala keeps breaking binary compatibility with every new release. In spite of previous promises, compatibility was broken in release 2.7, broken again in release 2.8 and broken yet again in 2.9. As I understand it, Scala language designers are forced to breaking compatibility whenever Scala library traits change in an incompatible way.

When a binary breakage occurs at the language level, the whole ecosystem for the language has to align itself with the new release. This is an extremely painful process affecting all users of the language. Even if a user does not want to upgrade to the latest and greatest Scala release, as long as a single tool, say T, in the tool-chain of the user upgrades and the user upgrades to the new version of T, then kaboom! All other project dependencies need to be upgraded as well.

If you decide to upgrade to the newest version of Scala in your project, you will also need to update every single dependency in your project (written in Scala). If you are lucky and every single dependency has made a release for the latest version of Scala, your project will build fine after the update. Otherwise, if a single dependency has not made the required release, you are left with two relatively unpleasant choices. You can either revert to the previous version of Scala or remove the non-compliant dependency.

If the Scala update was triggered by an IDE update, reverting to the older version of Scala may be particularly painful. If removing the non-compliant dependency is impossible, you will be hung out to dry.

As noted earlier, Scala language designers break compatibility for good technical reasons related to traits. The language is improved and cleaned up with every version, unlike Java which accumulates cruft. In other words, there is a good side to breaking compatibility. Preserving compatibility is an immensely intricate problem with a wide range of consequences. However, it is ultimately a political decision balancing between stability and change.

Once you have tasted the expressive power of Scala, it is hard to go back to program in Java. Once you have tasted the stability of Java, it is hard to put up with the brittleness of Scala. It's a non-ideal world out there.

Tooling proposed by Typesafe detects breakages and ensuring compatibility in minor versions. This tool is similar to clirr which has been around for a long time. Typesafe's response to the binary compatibility issue confirms my suspicions that the issue is still largely misunderstood by Typesafe. Typesafe subscription, the Migration manager or taking over a larger set of core libraries by Typesafe do not ensure that upgrading a project to the next version of Scala will go smoothly.

Assuming Scala continues to break compatibility in the foreseeable future, then I'll go out on a limb and make the following predictions:

The current situation limits the Scala user-base to a relatively small niche of enthusiasts. The small user-base hinders the development of a large Scala eco-system which further limit growth of the user-base, creating a vicious cycle.

Apparently, only few people complain about Scala's existing compatibility policy. Presumably, the Scala community has entered a comfort zone where existing users have grown accustomed to the current situation. For example, SBT makes it easy for authors of Scala libraries to generate artifacts for multiple versions of Scala. However, SBT is not suitable for projects which offer Scala-based extensions but otherwise are centered around Java. Thus, Scala's current compatibility policy makes it hard for Java projects to offer Scala-based extensions. I, for one, would love to offer a Scala-based configurator for logback (in addition to XML and Groovy based configurators) but have no intention of migrating our build to SBT.

One might also forget that the vast vast majority of developers will vote with their feet. They will simply walk away instead of engaging the Scala community for the preservation of binary compatibility. This, Scala will probably continue to be attractive for projects where occasional compatibility breakages are acceptable. Of course, the set of projects where breakages are unacceptable is... non-negligible.

The upcoming Java 8 with support closures will be a big leap forward for the Java platform. Competing languages will eventually close the gap, and Scala will stop being cool.


steve said...

Mhhh. Looks like you missed the whole last year.

- The binary changes between 2.x releases are exactly as specified. Binary compatibility is only a concern between 2.x.y releases. The x-part of the version number is like the Java X, where also binary incompatible changes appear.

- The tools for detecting breakage already exist.

- Language level primitives are already deployed and being used in the version shipping to day.

Because this has been discussed to death last year already and concerns have been addressed appropriately, I won't repeat everything again.

Considering that Scala developers are not always ex-Java developers, I think these requests show that many people stuck in the Java-legacy world consider themselves to be much more important than they actually are.

In my experience, developers don't have much problems with the current strategy of "recompile, be happy".

Ceki said...


1) Are you real?

2) If you are real, then you are just going to alienate people with your attitude.

steve said...

1) No, of course not. ^^

2) Care to tell me where I'm mistaken?

Ceki said...

FYI, code compiled against java 1.1 will run under Java version 1.1 and any subsequent version of Java. More generally, code compiled against Java version N will run perfectly under version N and any subsequent version of Java.

In the Scala world, the same does not hold true. Code compiled against Scala 2.7 will not run under subsequent versions such as 2.8 or 2.9. This limitation is unrelated to legacy code written in Java. It renders any Scala project with many dependencies predictably unstable.

The "recompile-to-upgrade" strategy maybe OK for certain projects. It would however be an untenable strategy if Scala had massive market penetration. In fact, this strategy ensures that Scala never gains wide acceptance.

steve said...

Not really. Just look at the breakage which occurred during the migration at that time. Add the changes to the memory model, to threading, ...
Considering that most packages are exempted from any compatibility guarantees in Java SE and the changes to javax, Swing and AWT, deprecation of JVMDI and JVMPI, breakages due to Classloader, compiler changes, assertion facilities, Generics and dozen of other changes, in my opinion Java's claims about backwards compatibility are mostly based on good marketing.

If Scala would adopt Java's compatibility shackles and stop actually removing deprecated elements, couldn't people just use Java in the first place? I'm pretty happy that the whole deprecated compatibility stuff from 2.7/2.8 is finally gone now. The libraries are much cleaner and simpler and JAR sizes went down.

If people are unable to schedule even a single "maintenance day" for their code approx. every 24 months, Scala probably isn't for them.
That's why I argue that it doesn't make sense to cater to every wish of hardcore Java fans: Java is the best for them, they will never use something else, let them be happy and concentrate on features in Scala which people actually need and appreciate.

But actually, aren't these problems solved when the Migration Manager can just rewrite JARs to the version requested, without requiring or touching the source code?

Java's JAR hell being one of the reason for a new module system, isn't that actually a good proof for the troubles occurring in Java if one library decides to update one of it's dependencies and every other library needing a different version just breaks?

Regarding Scala 2.7/2.8/2.9 ... this has been discussed already over a year ago and if you care, you can google why 3.0 has been named "2.8" instead. The situation at that time was quite comparable to "Java 1.5.0" vs. "Java 5". But people got over it and moved on.

I'm not too concerned about Scala's wide acceptance. There are dozens of popular languages out there where users are pretty impressed about Scala's level of source compatibility. Java is the only language trying to be backward compatible at the price of lacking good libraries and necessary features (Filessystem API 15 years late, Date&Time still missing, Closures maybe in Java 8, ...).

I just want to point out that the Java-centric world view is not the only valid one and Scala not obeying to every rule Java made up is not blasphemy.

Steven said...

(Different Steve here...)

If the Scala update was triggered by an IDE update, reverting to the older version of Scala may be particularly painful. If removing the non-compliant dependency is impossible, you will be hung out to dry.

This reminded me of my painful attempt to use the latest Scala Eclipse plugin, which mysteriously required the not-yet final Scala 2.9.2 version. I couldn't resolve the library dependencies on my small project. I eventually had to abandon Eclipse, because it was too much work to try and revert to the old plugin.

Ceki said...

Hello different Steve,
The case you describe sounds like a momentary window of breakage rather than a long term structural failure.

Presumably Scala 2.9.2 will be released shortly and you will be able to use packages compiles against 2.9.x without problems.

AlBlue said...

I've been complaining about this for years – here's my tale on it two years ago:

Unfortunately whilst Scala still holds out hope, in reality it had little chance of succeeding in the long term because systems written in Scala essentially become unmaintainable.

In the days of C, and certainly prior to Linux distributions, the mantra of "recompile from source" was the norm. Java changed all that and has been so successful precisely because of backward compatibility.

However none of the recent financial injections into the Scala marketplace appear to be addressing the real crux of the problem, and so it is likely to stay where it is - a niche language for certain tasks.

Ceki said...

I also think that setting a higher priority for preserving compatibility is the key here. If Scala users ask for it respectfully and in numbers, it is more likely to happen.

Unknown said...

Very interesting reading