Question

Consider:

object implicitnull extends App {
  mymethod

  implicit val arg = "foo"

  def mymethod(implicit arg: String) = {
    arg.size
  }
}

This does not cause any compilation error, however, at runtime results in NullPointerException coming from arg.size.

Is this the intended behavior?

Was it helpful?

Solution

Yes it's the intended behavior due to the way Scala constructs classes and initializes them. Consider this example:

scala> class A {
     |   f
     | 
     |   implicit val arg = "foo"
     | 
     |   def f(implicit arg: String) = {
     |     println(arg)
     |   }
     | }
defined class A

scala> class B {
     |   f(arg)
     | 
     |   val arg = "foo"
     | 
     |   def f(implicit arg: String) = {
     |     println(arg)
     |   }
     | }
defined class B

scala> class C {
     |   implicit val arg = "foo"
     | 
     |   f
     | 
     |   def f(implicit arg: String) = {
     |     println(arg)
     |   }
     | }
defined class C

scala> new A
null
res0: A = A@67d3caf

scala> new B
null
res1: B = B@3f2c5ad4

scala> new C
foo
res2: C = C@177bdd23

At the moment the function f is invoked in class C the value has been initialized, while in class B it has been not initialized yet. Class A is exactly the same as class B - the only difference is that Scala passes the arg implicitly in A.

It's a little bit confusing because this code is doing 2 things - it's declaring member variables and executing constructor code. If you take class B for example, val arg would be declared at the point where f is called, but not initialized yet. val arg = "foo" does the initialization. Once you translate this to Java it becomes more obvious:

public class B {

    void f(String arg) {
        System.out.println(arg);
    }

    String arg; // also acts as final in Scala

    public B() {
        f(arg);
        arg = "foo";
    }
}

Using lazy val or correct initialization order will help to fix it:

scala> class B {
     |   f(arg)
     | 
     |   lazy val arg = "foo"
     | 
     |   def f(implicit arg: String) = {
     |     println(arg)
     |   }
     | }
defined class B

scala> new B
foo
res3: B = B@3f9ac6e6
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top