Is this the proper way to initialize null references in Scala?
Solution 1:
Alternatives
Use null
as a last resort. As already mentioned, Option
replaces most usages of null. If you using null
to implement deferred initialisation of a field with some expensive calculation, you should use a lazy val
.
Canonical initialisation to null
That said, Scala does support null
. I personally use it in combination with Spring Dependency Injection.
Your code is perfectly valid. However, I suggest that you use var t: T = _
to initialize t
to it's default value. If T
is a primitive, you get the default specific to the type. Otherwise you get null
.
Not only is this more concise, but it is necessary when you don't know in advance what T
will be:
scala> class A[T] { var t: T = _ }
defined class A
scala> new A[String].t
res0: String = null
scala> new A[Object].t
res1: java.lang.Object = null
scala> new A[Int].t
res2: Int = 0
scala> new A[Byte].t
res3: Byte = 0
scala> new A[Boolean].t
res4: Boolean = false
scala> new A[Any].t
res5: Any = null
Advanced
Using var t: T= null
is a compile error if T is unbounded:
scala> class A[T] { var t: T = null }
<console>:5: error: type mismatch;
found : Null(null)
required: T
class A[T] { var t: T = null }
You can add an implicit parameter as evidence that T
is nullable -- a subtype of AnyRef
not a subtype of NotNull
This isn't fully baked, even in Scala 2.8, so just consider it a curiousity for now.
scala> class A[T](implicit ev: Null <:< T) { var t: T = null }
defined class A
Solution 2:
The canonical answer is don't use null. Instead, use an option type:
var a = None : Option[MyObject]
When you want to set it:
a = Some(foo)
And when you want to read from it, test for None:
a match {
case None => Console.println("not here")
case Some(value) => Console.println("got: "+value)
}
Solution 3:
As David and retronym have already mentioned, it's a good idea to use Option
in most cases, as Option
makes it more obvious that you have to handle a no-result situation. However, returning Some(x)
requires an object creation, and calling .get
or .getOrElse
can be more expensive than an if-statement. Thus, in high-performance code, using Option
is not always the best strategy (especially in collection-lookup code, where you may look up a value very many times and do not want correspondingly many object creations). Then again, if you're doing something like returning the text of an entire web page (which might not exist), there's no reason not to use Option.
Also, just to add to retronym's point on generics with null
, you can do this in a fully-baked way if you really mean it should be null
:
class A[T >: Null] { var t: T = null }
and this works in 2.7 and 2.8. It's a little less general than the <:<
method, because it doesn't obey NotNull
AFAIK, but it otherwise does exactly what you'd hope it would do.