Forward References - why does this code compile?

后端 未结 2 1792
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-30 05:34

Consider this snippet:

 object A {
     val b = c
     val c = \"foo\"
 }
 println( A.b )   // prints \"null\"

As part of a larger program,

相关标签:
2条回答
  • 2020-11-30 06:12

    The body of a class or an object is the primary constructor. A constructor, like a method, is a sequence of statements that are executed in order -- to do anything else, it would have to be a very different language. I'm pretty sure you wouldn't like for Scala to execute the statements of your methods in any other order than sequential.

    The problem here is that the body of classes and objects are also the declaration of members, and this is the source of your confusion. You see val declarations as being precisely that: a declarative form of programming, like a Prolog program or an XML configuration file. But they are really two things:

    // This is the declarative part
    object A {
      val b
      val c
    }
    
    // This is the constructor part
    object A {
      b = c
      c = "foo"
    }
    

    Another part of your problem is that your example is very simple. It is a special case in which a certain behavior seems to make sense. But consider something like:

    abstract class A {
      def c: String
    }
    
    class B extends A {
      val b = c
      override val c = "foo"
    }
    
    class C extends { override val c = "foobar" } with B
    
    val x = new C
    println(x.b)
    println(x.c)
    

    What do you expect to happen? The semantics of constructor execution guarantees two things:

    1. Predictability. You might find it non-intuitive at first, but the rules are clear and relatively easy to follow.
    2. Subclasses can depend on superclasses having initialized themselves (and, therefore, its methods being available).

    Output:

    it will print "foobar" twice for more => https://docs.scala-lang.org/tutorials/FAQ/initialization-order.html

    0 讨论(0)
  • 2020-11-30 06:28

    It is because of outdated version of Scala.

    With Scala 2.11.5 it compiled with warning or doesn't compiled at all:

    C:\Users\Andriy\Projects\com\github\plokhotnyuk>scala
    Welcome to Scala version 2.11.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_31).
    Type in expressions to have them evaluated.
    Type :help for more information.
    
    scala> { object A { val b = c; val c = "foo" }; println(A.b) }
    <console>:9: warning: Reference to uninitialized value c
                  { object A { val b = c; val c = "foo" }; println(A.b) }
                                       ^
    null
    
    scala> { val b = c; val c = "foo"; println(A.b) }
    <console>:9: error: forward reference extends over definition of value b
                  { val b = c; val c = "foo"; println(A.b) }
                            ^
    
    0 讨论(0)
提交回复
热议问题