-
Notifications
You must be signed in to change notification settings - Fork 21
Object's initialization order #9115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Imported From: https://issues.scala-lang.org/browse/SI-9115?orig=1 |
@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 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. |
The problem is illustrated by the example below: ``` Scala class Foo(val opposite: Foo) case object A extends Foo(B) // A -> B case object B extends Foo(A) // B -> A ``` The check aims to be simple for programmers to understand, expressive, fast, and sound. The check is centered around two design ideas: (1) initialization-time irrelevance; (2) partial ordering. The check enforces the principle of _initialization-time irrelevance_, which means that the time when a static object is initialized should not change program semantics. For that purpose, it enforces the following rule: > **The initialization of a static object should not directly or indirectly read or write mutable state owned by another static object**. This principle not only puts the initialization of static objects on a solid foundation but also avoids whole-program analysis. Partial ordering means that the initialization dependencies of static objects form a directed-acyclic graph (DAG). No cycles with length bigger than 1 allowed --- which might lead to deadlocks in the presence of concurrency and strong coupling & subtle contracts between objects. Related Issues: #16152 #9176 #11262 scala/bug#9312 scala/bug#9115 scala/bug#9261 scala/bug#5366 scala/bug#9360
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 |
scala/scala3#21444 has an even simpler reproducer and some fresh discussion. |
Example:
Results :
After re-definition of
D
: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 makeaaa
available before D1 initializes, it shoudn't work that way for cases, likeD.D1
.The text was updated successfully, but these errors were encountered: