56

Let's say I have a MyObject instance which is not initialized:

var a:MyObject = null

is this the proper way to initialize it to null?

Geo
  • 93,257
  • 117
  • 344
  • 520
  • I think this gets an error if `a` is later assigned something. Which is why I think this is a valid question: in the old days an object can be null, but now this option is no longer available and we're forced to use "option" explicitly, adding to bulky code. – Yan King Yin Mar 13 '15 at 01:07
  • 1
    @YanKingYin No, this code correctly makes a variable that can be assigned to with real instances of `MyObject`. When trying to write this code, it's easy to make the mistake of writing `var a = null`, which declares the variable `a` of type `Null`, which is uninstantiable. Using `var a:MyObject = null` declares `a` with type `MyObject`, allowing it to hold references to instances of `MyType` later. Options are safer than using nulls directly, but they are optional. – Theodore Murdock Jul 06 '16 at 21:53
  • Not according to IntelliJ. – Alonso del Arte Mar 10 '21 at 20:52

4 Answers4

69

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
Balázs Németh
  • 6,222
  • 9
  • 45
  • 60
retronym
  • 54,768
  • 12
  • 155
  • 168
  • 9
    What's that <:< thing there? – Dimitris Andreou May 11 '10 at 13:02
  • 1
    Very helpful! But why does it NOT suffice to put an upper bound of AnyRef on T, i.e. `class A[ T <: AnyRef ] { var t:T = null }` ? – AmigoNico Dec 11 '12 at 03:29
  • Scala has an experimental trait, `NotNull`. If we have `class C extends NotNull`, `null` is not a subtype of `C`. This feature was turned off by default in Scala 2.8, as it isn't fully baked. But it is still around enough to mean you have to write `class A[T >: Null] { var t: T = null }` rather than `class A[T <: AnyRef] { var t: T = null }` – retronym Dec 11 '12 at 21:35
  • How to achieve initializing an Int to null, as I want to store the value null in database instead of default 0 – greperror May 04 '17 at 09:31
  • @DimitrisAndreou The answer can be found [elsewhere on the stack](https://stackoverflow.com/questions/3427345/what-do-and-mean-in-scala-2-8-and-where-are-they-documented) –  Feb 28 '19 at 08:01
  • write `null` instead of `_` is more concise, this probably is the worst reason to use something. `_` in scala could mean dozens of different thing. `null` does mean no value. Save 3 characters have a headache instead. – Kiwy Jun 19 '19 at 10:30
32

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)
}
David Crawshaw
  • 10,427
  • 6
  • 37
  • 39
  • 15
    As an aside, the canonical way to handle `Option` variables is **not** to use pattern matching, but to use collection/monad operations such as `map`, `getOrElse`, `flatMap`, `foreach`, `toList`, `filter` etc. For the example you gave, pattern matching seems to makes sense because you're taking distinct actions in each case, but in the majority of real scenarios the `None`s can be coerced out without being explicitly referenced. – Andrzej Doyle Feb 08 '11 at 12:11
9

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.

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
-1

I came across this question since scalastyle told me to not use null when initialising an object within my test with null.

My solution without changing any type that satisfied scalastyle:

var a: MyObject = (None: Option[MyObject]).orNull
Guenter
  • 106
  • 7