Skip to content
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

Object's initialization order #9115

Open
scabug opened this issue Jan 26, 2015 · 9 comments
Open

Object's initialization order #9115

scabug opened this issue Jan 26, 2015 · 9 comments
Labels
Milestone

Comments

@scabug
Copy link

scabug commented Jan 26, 2015

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.

@scabug
Copy link
Author

scabug commented Jan 26, 2015

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

@scabug
Copy link
Author

scabug commented Jan 27, 2015

@retronym said:
Might be the same issue as #5304.

@scabug
Copy link
Author

scabug commented Jan 27, 2015

@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)
  }
}

@dk14
Copy link

dk14 commented Aug 4, 2018

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.

@SethTisue SethTisue changed the title Object's intialization order Object's initialization order Aug 4, 2018
@dk14
Copy link

dk14 commented Aug 6, 2018

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?

@som-snytt
Copy link

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.

liufengyun added a commit to scala/scala3 that referenced this issue Jun 16, 2023
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
@SethTisue SethTisue added fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) and removed fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) labels Feb 16, 2024
@SethTisue
Copy link
Member

let's consolidate on #5304

@SethTisue SethTisue closed this as not planned Won't fix, can't repro, duplicate, stale Feb 16, 2024
@SethTisue SethTisue reopened this Aug 29, 2024
@SethTisue
Copy link
Member

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

@SethTisue SethTisue added this to the Backlog milestone Aug 29, 2024
@SethTisue
Copy link
Member

scala/scala3#21444 has an even simpler reproducer and some fresh discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants