6

Why when I use reference this in a variable declaration, illegal forward reference doesn't appear? What's the difference between declaration with this and without it?

The following example fails to compile because of the illegal forward reference:

class FailsToCompile {
    int a = b; //illegal forward reference
    int b = 10;
}

By qualifying the use of b by this the compilation error goes away.

class Compiles {
    int a = this.b; //that's ok
    int b = 10;
}
michid
  • 10,536
  • 3
  • 32
  • 59
Dmitry
  • 63
  • 5
  • Possibly related (although it is about static field) [Why illegal forward reference error not shown while using static variable with class name](https://stackoverflow.com/q/29153703) – Pshemo May 02 '19 at 09:43
  • 1
    @Pshemo I think the mechanics behind it are the same, aren't they? So that should count as a duplicate – Lino May 02 '19 at 09:44
  • 1
    @Lino You are probably right, but since I didn't read that post yet I don't want to use my dupe-hammer based just on probability. – Pshemo May 02 '19 at 09:46
  • 3
    Welcome to Stack Overflow! Please read "How to create a [mcve]". Then use the [edit] link to improve your question (do not add more information via comments). Otherwise we are not able to answer your question and help you. Meaning: **scope** is extremely important here, and your code snippets leave out the scope completely! – GhostCat May 02 '19 at 09:48
  • I suggest (based on no solid evidence) that the prohibition on forward references is merely a best-effort attempt ["to catch, at compile time, circular or otherwise malformed initializations"](https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#d5e12805). For example, you can also forward-reference a variable through a method invocation. So, it catches obviously-wrong code, but just doesn't try too hard to stop you if you are really going to insist you know what you're doing. – Andy Turner May 02 '19 at 10:06
  • *The use is a simple name in either an instance variable initializer of C or an instance initializer of C...* that **simple name** is very very bothering, I never understood this part of the documentation and the need for it... basically it's not an error because the JLS says so and `javac` conforms to that rule, a questionable rule if you ask me – Eugene May 02 '19 at 11:58

1 Answers1

6

Assuming the following class

public class MyClass {
    int a = b;
    int b = 10;
}

The JLS 8.3.3. states in your case :

Use of instance variables whose declarations appear textually after the use is sometimes restricted
- The use is a simple name in either an instance variable initializer of C or an instance initializer of C

Now, using the member this allows you to access an instance that is already declared with default values ( a = 0, b = 0 ) but not yet fully initialized. This is visible if you check the result of:

public class MyClass {
    int a = this.b;
    int b = 10;
}

You would not get the expected value :

new MyClass().a //0
new MyClass().b //10

I can't explain why this is legal exactly since this would never give a correct value. We can find some explanation about why the restriction exist :

The restrictions above are designed to catch, at compile time, circular or otherwise malformed initializations.

But why allowing this to works...


Knowing that during an initialization of an instance, the following actions occurs :

  1. Member declaration
  2. Block execution and Field initialization in order
  3. Constructor execution

Give some strange behavior:

public class MyClass {

    {
        b = 10;
    }
    int a = this.b;
    int b = 5;
    {
        b = 15;
    }

    public static void main(String[] args) {
        MyClass m = new MyClass();
        System.out.println(m.a); //10
        System.out.println(m.b); //15
    }
}

I would limit the initialization in the constructor.

AxelH
  • 14,325
  • 2
  • 25
  • 55