Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forward References - why does this code compile?

Consider this snippet:

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

As part of a larger program, this would lead to a failure at runtime. The compiler apparently permits the forward reference from 'b' to (uninitialized) 'c' but 'b' is left with c's original null value. Why is this permitted? Are there programming scenarios that would benefit from this feature?

Change the code to a straight sequence and the behavior changes:

 val b = c  val c = "foo"  println( b )   // prints "foo" 

Why is the behavior different? And why does this even work? Thanks.

Update 1:

The question came up how I ran the second example. I simplified the setup a bit and compiled it using Scala 2.9.0.1 inside IntelliJ IDEA 10.5.2 with the latest Scala plugin. Here is the exact code, in a freshly created and otherwise empty project, which I am using to test this, which compiles and runs fine in this environment:

 package test  object Main {      def main( args: Array[String] ) {        val b = c        val c = "foo"        println( b )   // prints "foo"     }  } 

For what it's worth, IDEA also thinks (when I click "through" the reference to 'c' in val b = c) that I am referring to the (later) declaration of 'c'.

like image 336
Gregor Scheidt Avatar asked Oct 14 '11 03:10

Gregor Scheidt


People also ask

What is forward referencing in compiler design?

A forward reference occurs when a label is used as an operand, for example as a branch target, earlier in the code than the definition of the label. The assembler cannot know the address of the forward reference label until it reads the definition of the label.

What is forwarded reference?

2.11 Forward References Using an identifier before its declaration is called a forward reference, and results in an error, except in the following cases: When a goto statement refers to a statement label before the label's declaration. When a structure, union, or enumeration tag is used before it is declared.

What is meant by a forward reference in C?

Forward reference is when you declare a type but do not define it. It allows you to use the type by pointer (or reference for C++) but you cannot declare a variable. This is a way to say to the compiler that something exists. Say that you have a Plop structure defined in Plop.

What is forward reference in Java?

In simple terms it means referencing (accessing a variable, calling a function) that is further down in the code file. static int x=getY(); static int y=5; static int getY() { return y; } x's value is set to the result of getY() getY() is called before y's value is set to 5. x's value is therefore 0 (default integer)


1 Answers

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

like image 121
Daniel C. Sobral Avatar answered Oct 14 '22 07:10

Daniel C. Sobral