bug
bug copied to clipboard
Object's initialization order
Example:
object D {
def aaa = 1 //that’s the reason
class Z (depends: Any)
case object D1 extends Z(aaa) // 'null' when calling D.D1 first time
case object D2 extends Z(aaa) // 'null' when calling D.D2 first time
println(D1)
println(D2)
}
Results :
defined object D
scala> D.D1
null
D2
res32: D.D1.type = D1
After re-definition of D:
defined object D
scala> D.D2
D1
null
res34: D.D2.type = D2
So it forgots (or blocks) to initialize the requested sub-object if it refers to some another member of object inside sub-object definition (aaa inside constructor works fine) before running enclosing object initialization. It initializes this sub-object after (when aaa is defined). Even if it's intended to initialize enclosing object to make aaa available before D1 initializes, it shoudn't work that way for cases, like D.D1.
Imported From: https://issues.scala-lang.org/browse/SI-9115?orig=1 Reporter: Dmytro Kondratiuk (dk14) Affected Versions: 2.11.4, 2.11.5 See #5304, #5366
@retronym said: Might be the same issue as #5304.
@retronym said:
class Z (depends: Any)
object D {
object D1 extends Z(D)
// object D2 extends Z(D.hashCode) // 'null' when calling D.D2 first time
println(Thread.currentThread.getStackTrace.mkString("\n", "\n", ""))
// D$.<init>(test.scala:9)
// D$.<clinit>(test.scala)
// D$D1$.<init>(test.scala:6)
// D$D1$.<clinit>(test.scala)
// Test$.main(test.scala:25)
// Test.main(test.scala)
System.out.println(D1)
}
object Test {
def main(args: Array[String]): Unit = {
// Due to SI-5304, the compiler initializes the class
// D$D1$ *before* D$. the constructor for D$D1 then
// initializes D$, which reveals the unitialized value of
// D$D1$.MODULE$ (this singleton instance of D.D1)
D.D1
// This would have avoided the initialization order trap:
{D; D.D1}
// It has been argued that the compiler really should do automatically,
// (SI-5304), but changing the semantics like this comes with
// its own set of risks (e.g performance)
}
}
Given that both this example (#9115) and #5304 actually work in Dotty (0.9.0-RC1), though remain unsolved in Scala2 literally for years (I just checked 2.12.6, 2.13.0-M4), maybe it makes sense to at least close this one as a duplicate of 5304 and keep the latter for 2 more years ahead :) [or until migrational Scala 2 release]. Or is there some kind of fixed_in_dotty label to put it on both issues?
As an OP of #9115 - I wouldn't mind either scenario.
After rethinking the whole "Fixed In Dotty" meme, I wonder if there any regression tests planned (or in place) on those issues (9115, 5304 etc), given that some migrational tweaks might cause some bugs to come back in Scala3?
The comment suggesting "fixed in dotty" is obsolete (wrong). If the label had been applied, I would remove it now. The dotty link is for the init checker; I don't know whether there is even an intention to offer an operational fix when a problem is detected. (Just detecting is still WIP, IIUC.)
I'd suggest not conflating this issue and 5304, which I read or have read as pertaining just to rewriting case class constructors in RefChecks. That is, I suggest keeping both issues open as not duplicate. Both issues have to do with forcing object init.
Dotty from summer 2018 was 0.8.0, but I'm unable to build it either in repo or github download.
let's consolidate on #5304
it seems the consolidation was a bit over-eager, as Som has pointed out that Scala 3 doesn't have 5304 but does have this one
https://github.com/scala/scala3/issues/21444 has an even simpler reproducer and some fresh discussion.