I would like to use a value from a particular (singleton) object as a default argument for a class constructor. (The object is not the companion object of the class.) It compiles, but when I run it, I get a java.lang.ExceptionInInitializerError. I guess it has something to do with the order of initialization by the compiler of the object and the class constructor. Is there any way to do that without getting this error? Thanks.
Could you share the code? It might make it easier for people to help.
object Foo
val bar = 2
case class Bar(bar: Int = Foo.bar)
I’m not able to reproduce the problem:
Welcome to Scala 3.1.1 (1.8.0_322, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
scala> object Foo:
| val bar = 2
|
| case class Bar(bar: Int = Foo.bar)
// defined object Foo
// defined case class Bar
scala> Bar()
val res0: Bar = Bar(2)
If you shared a reproduction via https://scastie.scala-lang.org we’d be absolutely sure we’re all on the same page — same code, same versions of things, same error message…
If the object and the class are defined in the same source file, this issue does not come up. As far as I know, the problem occurs only if they are defined in different source files. That being the case, I don’t think it can be replicated in the REPL or Scastie.
I thought it was an initialization order issue. If the case class is compiled before the object, the default argument value is uninitialized. Or that’s what I thought anyway. Actually, I thought this was a fairly well known issue, and I was just wondering what the best alternative or work-around is.
Are you sure you’ve fully minimized? I put
object Foo:
val bar = 2
in one file and
case class Bar(bar: Int = Foo.bar)
@main def doIt() = {
println(Bar())
}
in another and everything works (with 3.1.2-RC1). There’s some chance that you have a circular dependency somewhere (i.e. Foo
might depend on Bar
being initialized without you realizing it)
Also, the missing :
after Foo
was presumably a typo?
And just to add: compilation order is irrelevant – all that matters is which object
is referenced first in execution of the program. That’s when object initialization happens.
OK, thanks. I’ll check for a circular dependency.