Chris W.
Chris W.

Reputation: 2366

Scala Weird Class/Object initalization in Traits

I can't find an answer why this code throws an exception for assertProperChildren(Zoo2), but only if Zoo2.Tiger is accessed before making the assert. If you comment that access line, all asserts work. Doesn't make sense to me. Is this a known Scala bug?

trait Domain {
  abstract class ChildDomain
  def children: Seq[ChildDomain]
}

// V1
abstract class Zoo1 extends Domain {
  object Tiger extends ChildDomain
  val children = Seq(Tiger)
}
object Zoo1 extends Zoo1

// V2
object Zoo2 extends Domain {
  object Tiger extends ChildDomain
  val children = Seq(Tiger)
}

// V3
object Zoo3 extends Domain {
  object Tiger extends ChildDomain
  lazy val children = Seq(Tiger)
}

object Main {
  def main(args: Array[String]): Unit = {
    def assertProperChildren(domain: Domain) = {
      assert(!domain.children.contains(null))
    }
    Zoo1.Tiger
    // Will NOT crash here, even if we touch Zoo1.Tiger before Zoo1
    assertProperChildren(Zoo1)
    Zoo2.Tiger
    // Will crash here, but only if we touch Zoo2.Tiger before Zoo2
    assertProperChildren(Zoo2)
    // So if we want a scala object directly inheriting from a Domain
    // we need lazy children:
    Zoo3.Tiger
    assertProperChildren(Zoo3)
  }
}

Upvotes: 1

Views: 51

Answers (1)

Shankar Shastri
Shankar Shastri

Reputation: 1154

Scala follows initialization order, it's explained in the below link as FAQs. https://docs.scala-lang.org/tutorials/FAQ/initialization-order.html

You can use -Xcheckinit as part of scalac flag. To validate the same.

Upvotes: 1

Related Questions