There are two ways to handle missing data in Scala: variables of reference type may hold null, and there is Option[T].
However, there is no statically checked way to prevent a reference variable from holding null. Such a prevention would often make sense, e.g. for most uses of Option[T].
Tony Hoare invented null references, and now calls this his "billion dollar mistake". He says the solution is offered by Spec#, a proposal from Microsoft Research.
http://qconlondon.com/london-2009/presentation/Null+References:+The+Billion+Dollar+Mistake
http://research.microsoft.com/en-us/projects/specsharp/
Spec# has "non-null types" and "possibly-null types"; a possibly-null type has a question mark; assigning null to variables of non-null types would be illegal:
string? maybeAString = null;
string s = null; // error
This idea did not go mainstream.
C# got a Nullable<T> with shorthand notation T?, but only for a value type T.
Neither does Scala have non-null vs possibly-null reference types.
Could anybody explain why?
(This may be a dumb question. But I am curious, so I take the risk, even though this mail archive may last for thousands, if not millions of years)
If you could redesign Scala, how about
- give it a trait Nullable (rather than NotNull)
- forbid null assignments to references that do not inherit from Nullable
- treat features from Java classes as if they inherit from Nullable
- offer an escape mechanism for that treatment
There are two ways to handle missing data in Scala: variables of reference
type may hold null, and there is Option[T].
There have been some other approaches to it: http://medianetwork.oracle.com/video/player/1785452087001
So while it might sound great in theory, it is broken, cumbersome and painful in the Java reality we currently live in.
If it works out really that good, I hope it would not be too late for adoption by Scala.
Actually, these two lines belonged together: :-)
"broken, cumbersome and painful" was the description for the approach shown in the video. I hope Scala will never get near such a broken mess.
(...) sadly it is far worse than shown on the slides. Their proposal basically requires an "annotate every Java library on this planet with various @NonNull/@Nullable stuff" approach. And even this doesn't work properly, as shown by the @Kotlin annotations.
I think everyone can agree that nulls are from the devil and null pointer exceptions are his spawn. However, doing anything about it is complicated by Java interop and legacy. If I had the choice, I'd make every type T be disjoint from null except for `Nullable[T]`. It would be a compilation error to assign null to anything except Nullable[T], and un-annotated code from outside scala would be presumed to be Nullable types.
Hi Simon,
I think support for nullable vs not-null types should be just "compiler fiction". The extra information should be erased during compilation just like with generic type parameters; no enforcement by the JVM would be applicable. The support would not be 100% NPE-safe, but still be worthwhile, IMO.
I think most of your issues may adequately be tackled.
About casting null to a not-null type:
s.asInstanceOf[String]
should throw a NPE if s == null.def cast[A](a.Any) = a.asInstanceOf[A]
because the actual type parameter might be nullable. The compiler should give a warning here.Similarly, a compiler warning would flag a not-null array allocation such as
Likewise for parameterless constructors that are only needed for deserialisation, as witnessed by a specific annotation.
Reflection and Class#cast would not be affected.
Assignment would be as in:
s = ns!!
There should not be an interaction between nullable types and Optional[_]. Optional parameters should be specified with Optional[_], I think (now).
While this approach for not-null types has several gaps, I think many projects such as my current one, might benefit. The devils are in the details, of course. I would like to learn the experience from Kotlin.
André
I believe the point of using a language with an expressive type system is to try to converge the range of values that the type system allows a function to return with the range of values that are valid outputs of the function. So in type safety nirvana the types and the valid values are the sames.
Ironically Option, it you look at it precisely, moves away from this goal. If we have a function D => R defined in Scala (or Java) then the possible return values are: R | null
But if you change the signature to D => Option[R] then you can return:
Some(R) | Some(null) | None | null