Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does self-reference in the constructor counts as "escaping"?

Reading this article about JSR-133, it says:

all of the writes to final fields (and to variables reachable indirectly through those final fields) become "frozen," ...

If an object's reference is not allowed to escape during construction, then once a constructor has completed and a thread publishes a reference to an object, that object's final fields are guaranteed to be visible ...

The one caveat with initialization safety is that the object's reference must not "escape" its constructor -- the constructor should not publish, directly or indirectly, a reference to the object being constructed.

My question is about what is considered escaping. More specifically, I want to know if this (somewhat artificial and strange) code results in a safely-publishable Child object:

class Parent {
    /** NOT final. */
    private int answer;

    public int getAnswer() {
        return answer;
    }

    public void setAnswer(final int _answer) {
        answer = _answer;
    }
}

public class Child extends Parent {
    private final Object self;

    public Child() {
        super.setAnswer(42);
        self = this;
    }

    @Override
    public void setAnswer(final int _answer) {
        throw new UnsupportedOperationException();
    }
}
  1. Firstly, while Parent is clearly mutable, Child is "effectively immutable", since the parent setter that would allow mutability is not reachable anymore.
  2. The reference to "this" in the constructor is not visible to anyone (not getter, and not passed to any other object). So, does this count as "escaping"?
  3. But the object as a whole is being referenced by a final field (self), and so in theory, it's whole content should then be "frozen". OTOH, the final field is itself not reachable, so maybe it doesn't count; I could very well imagine the JIT just completely optimizing it away.
  4. If "self" was made accessible through a getter, but the getter is not called in the constructor, does it then count as escaping (assuming it didn't before)? This would prevent the JIT from optimizing it away, so that it must then "count", maybe?

So, is Child "safely-publishable", and if not, why, and would a getter for "self" change the answer?

In case the purpose of the question isn't clear, I think that if this works, it would allow one to easily make a mutable class "safely-publishable", by just extending it as shown above.

like image 913
Sebastien Diot Avatar asked Aug 28 '14 18:08

Sebastien Diot


1 Answers

You may be misunderstanding the meaning of escaping. The point is that the value of this must not reach any code foreign to the constructor. I think a few examples would explain it better:

  • setting a private field to this doesn't count as escaping;
  • calling a private method, which in turn doesn't call any further methods, and doesn't assign this to a foreign object's variable, doesn't count as escaping;
  • calling a public, overridable method belonging to this does count as escaping unless the class is final. Therefore your code lets this escape when you call setAnswer, not when you assign this to self. Why? Because a subclass may override this method and publish this to any foreign code.

A note on your reasoning about self: self is reachable from this and this doesn't depend on the fact that a foreign caller cannot get its value. It is enough that a method may internally dereference it. Anyway, the rules about freezing do not take into account the access level of variables. For example, everything is reachable via reflection.

like image 182
Marko Topolnik Avatar answered Oct 16 '22 12:10

Marko Topolnik