Correcting the Billion Dollar MistakeFebruary 1st, 2009 | by Jevgeni Kabanov | |
Last week I visited Stockholm to speak at the JFokus 2009. The event was quite spectacular, but for me the most interesting part occurred on the evening before the conference. I was sitting at the speaker’s dinner with Rickard Öberg, Kirk Pepperdine, Simon Ritter and a couple of others. For some reason or other I started talking to Simon about the problem that’s recently been on my mind. Perhaps it’s been eating me after legendary Tony Hoare said this:
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. [...] This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
Now since I have a background in functional languages, I know that null references are not necessary. Null value is a member of all types, but some types don’t have or need a natural notion of absence. In fact in Haskell there is no such thing as an “absent” value generic to all types — types either have to declare it explicitly or wrap the underlying value into a Maybe type that has a dedicated Nothing value.
So e.g. the List type has a notion of an empty list encoded into the type:
// Roughly: a list is an empty list // or a pair of a value and a list data List a = Nil | Cons a (List a)
While the only way to encode an absent structure is to use Maybe:
// To build a car you need at most one engine // and zero or more wheels :) buildCar :: Maybe Engine -> [Wheel] -> Car
So while I was discussing that with Simon, Kirk banged me on the head to get my attention (just joking, banging me on the head is nowhere near enough to get my attention). Apparently they were discussing more or less the same topic with Rickard, and he had a similar solution for Java. I assumed it was the widely discussed @NotNull annotation, but it was way cooler than that.
Basically in the beginning Rickard started by adding @NotNull support to Qi4J (BTW an amazing piece of engineering, definitely check it out), so that they could automatically insert runtime assertions for the parameters having the @NotNull annotations, something like that:
-
class Test {
-
void transfer(
-
@NotNull Account from,
-
Account to,
-
double amount) {
-
//…
-
}
-
-
// Succeeds
-
transfer(
-
new Account(“Bugs Bunny”), null, 1000000.0);
-
// Throws NullPointerException
-
transfer(
-
null, new Account(“Bugs Bunny”), 1000000.0);
-
}
-
}
However soon after that they discovered that they were inserting @NotNull-s everywhere. So they reverted the notion and decided that they will generate the not null assertions for all parameters except the ones marked as @Optional. And this was the point when I thought to myself “Jevgeni, this is exactly what you were looking for!” So I turn to Rickard and I say “Rickard, this is exactly what I was looking for! This is amazing!” In fact this truly is amazing as it’s exactly captures the semantics of the Maybe type that I liked so much in the functional languages.
After that we go into a discussion whether or not it is possible to validate this assertion during compile-time. Opinions were mixed on this one, though I personally am convinced that it shouldn’t be too easy (your opinion on the topic is welcome, also it will make a great master’s thesis topic). Eventually I get an idea and I say “Rickard, I bet I could implement a JavaRebel plugin that would check this at runtime in about half an hour in 50 lines of code”. And of course Rickard goes “No way!”, so I’m challenged. Next day I sit down for half an hour, then for another half an hour (there was no internet!) and voila — I have a working JavaRebel plugin (in less that 50 lines of code) that will make your methods throw an exception if you try to pass a null reference to a parameter not marked as @Optional (the plugin code deserves another post altogether). Of course I have to show this to Rickard (and he goes “No way!”) and we agree to somehow join forces to promote this sane approach (starting with having a single namespace for the @Optional annotation).
So what do we get? The previous example now looks like this:
-
@OptionalCheck
-
class Test {
-
void transfer(
-
Account from,
-
@Optional Account to,
-
double amount) {
-
//…
-
}
-
-
// Succeeds
-
transfer(
-
new Account(“Bugs Bunny”), null, 1000000.0);
-
// Throws NullPointerException
-
transfer(
-
null, new Account(“Bugs Bunny”), 1000000.0);
-
}
-
}
As you can understand if we make all of the code without the @Optional annotation to throw a NullPointerException for nulls we’ll break a lot of existing code. Therefore at the moment you also have to annotate the class where you want to enable such semantics with @OptionalCheck.
That’s pretty much it — you can download the plugin right away and just drop it in the classpath when JavaRebel is enabled (you’ll need a 2.0 milestone as 1.x was missing the necessary APIs). At the moment both annotations are in the org.optionalalliance package, but when it changes all you have to do is Organize Imports, so I won’t sweat the naming too much. Please do let us know what do you think of the approach and feel free to advocate it further :)
Cheers,
Jevgeni Kabanov
P.S. The plugin along with the source is also avalable in our Maven repository:
- URL: http://repos.zeroturnaround.com/maven2
- Group id:
org.zeroturnaround - Artifact id:
javarebel-optional-check-plugin