inconsistent implicit/circularity issue?

9 views
Skip to first unread message

AlanP

unread,
May 31, 2011, 5:30:18 PM5/31/11
to scala-user
I'm getting a behavior with implicits that does not seem consistent to
me. It is easier if I show it with code.

The following code in Exhibit 1(below) gets no compiler error, but
does trigger a NullPointerException at runtime. It can be fixed making
'val a' lazy, in object I. So it seems like an order of initialization
issue, except that it is between different objects that refer to each
other.

Then the code in Exhibit 2 is the same as Exhibit 1, except that
object A is being held directly in 'val a', instead of being inside a
List. In this case I get no runtime error, even without making 'a'
lazy, it runs as intended.

It seems to me that: 1) I should get the same behavior with Lists or
direct objects or, 2) I should be able to get a compile-time error on
Exhibit 1.

If this is the expected behavior, can someone explain me what's the
reasoning involved?

Thanks,

Alan

------ Exhibit 1 -------
trait C {val a: List[D]}

class D(implicit val c: C)

object ImplicitHolder {
implicit object I extends C {
val a = List(A) // can fix runtime error by making it lazy
}
}

import ImplicitHolder._

object A extends D {
val b = c.a.head
val s = "hello"
}

object Circularity extends App {
println(I.a.head.s)
}
--------------------------------

------ Exhibit 2 -----------
trait C {val a: D}

class D(implicit val c: C)

object ImplicitHolder {
implicit object I extends C {
val a = A
}
}

import ImplicitHolder._

object A extends D {
val b = c.a
val s = "hello"
}

object Circularity extends App {
println(I.a.s)
}
--------------------------

AlanP

unread,
May 31, 2011, 6:27:19 PM5/31/11
to scala-user
And I get same behavior under both 2.9.0 and 2.9.0-1. It's on github
as an sbt project if it helps: https://github.com/alanpog/Circularity
.
Tks,
Alan

Adriaan Moors

unread,
Jun 1, 2011, 1:57:46 AM6/1/11
to AlanP, scala-user
I don't think this is related to implicits. The initialisation semantics of objects should explain the behaviour, but I'll leave that to someone else to verify.

Here's my explicit version of exhibit 1, which exhibits the same runtime behaviour:

trait C {val a: List[D]}

class D( val c: C)

object Holder {
        object I extends C {
               val a = List(A)  // can fix runtime error by making it lazy
       }
}

import Holder._

object A extends D(I) {
       val b = c.a.head
       val s = "hello"
}

object Circularity extends App {
       println(I.a.head.s)
}

You might want to check out scalac's -Xcheckinit command-line option and related postings.

cheers
adriaan
Reply all
Reply to author
Forward
0 new messages