A small exercise

S

Stefan Ram

Try to predict the behavior of the execution or compilation
of the following code!

public class Main
{ final int a; final int b;
Main(){ this.a = 0; Main.this.b = 0; }
public static void Main( final java.lang.String[] args )
{ new Main(); }}

(I made this observation while programming something else
using Oracle JDK 7, but I have not read the JLS about it yet.)
 
A

Arne Vajhøj

public class Main
{ final int a; final int b;
Main(){ this.a = 0; Main.this.b = 0; }
public static void Main( final java.lang.String[] args )
{ new Main(); }}

My first thought was that it would not run without a
Main method. And it will not.

But a test compile revealed a compile error for
trying to assign to a final variable b and I guess that
is what is puzzling you.

I am puzzled too. The difference between this and
Main.this should be none.

But I don't think it is a problem one should encounter in real code.

Arne
 
S

Stefan Ram

Arne Vajhøj said:
public class Main
{ final int a; final int b;
Main(){ this.a = 0; Main.this.b = 0; }
public static void Main( final java.lang.String[] args )
{ new Main(); }}
My first thought was that it would not run without a
Main method. And it will not.

»Main(« was not an intentional distraction, but just
a typo. It was intended to be »main(«.
 
R

Roedy Green

»Main(« was not an intentional distraction, but just
a typo. It was intended to be »main(«.

I think you had it right the first time. This is not the main
static method but the Main constructor.
 
A

Arne Vajhøj

Try to predict the behavior of the execution or compilation
of the following code!

public class Main
{ final int a; final int b;
Main(){ this.a = 0; Main.this.b = 0; }
public static void Main( final java.lang.String[] args )
{ new Main(); }}

(I made this observation while programming something else
using Oracle JDK 7, but I have not read the JLS about it yet.)

open-jdk6 and open-jdk7

I think that logically, Main.this.b refers to the enclosing *instance*
which implies that the class has been instantiated, final fields can
only be initialized once in a constructor so trying to (logically)
assign a value to a final variable after instantiation is illegal.

I think :-|

If you remove the final modifier from b then the code compiles, but then
you know this already.

My understanding of the question is that it is why a work but not b
as this and Main.this should be the same.

Arne
 
A

Arne Vajhøj

On 20/04/13 14:11, Stefan Ram wrote:
Try to predict the behavior of the execution or compilation
of the following code!

public class Main
{ final int a; final int b;
Main(){ this.a = 0; Main.this.b = 0; }
public static void Main( final java.lang.String[] args )
{ new Main(); }}

(I made this observation while programming something else
using Oracle JDK 7, but I have not read the JLS about it yet.)

open-jdk6 and open-jdk7

I think that logically, Main.this.b refers to the enclosing *instance*
which implies that the class has been instantiated, final fields can
only be initialized once in a constructor so trying to (logically)
assign a value to a final variable after instantiation is illegal.

I think :-|

If you remove the final modifier from b then the code compiles, but then
you know this already.

My understanding of the question is that it is why a work but not b
as this and Main.this should be the same.

Yes, this is what I understood.

implies that the >>Main.this.b<< assignment occurs after instantiation
which would be illegal which is why the compiler complains.

For the given code this and Main.this refer to the same object.

And I don't see the implication you mention - in fact the so called
implication is not true for the provided code.

Arne
 
D

Daniele Futtorovic

Try to predict the behavior of the execution or compilation
of the following code!

public class Main
{ final int a; final int b;
Main(){ this.a = 0; Main.this.b = 0; }
public static void Main( final java.lang.String[] args )
{ new Main(); }}

(I made this observation while programming something else
using Oracle JDK 7, but I have not read the JLS about it yet.)

It is weird indeed that the compilation should yield the following error:
Main.java:3: error: cannot assign a value to final variable b
Main(){ this.a = 0; Main.this.b = 0; }
^
1 error

In section 15.11.1., /Field Access Using a Primary/
(<http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.11>),
the JLS states:
"At run time, the result of the field access expression is computed as
follows:
(...)
If the field is not static:
(...)
If the field is not final, or is a blank final and the field access
occurs in a constructor, then the result is a variable, namely the named
member field in type T found in the object referenced by the value of
the Primary."

So it should be all right.

Then again, perhaps the following plays a role; the same section also
states:
"At run time, the result of the field access expression is computed as
follows: (assuming that the program is correct with respect to definite
assignment analysis, i.e. every blank final variable is definitely
assigned before access)" (note the bit in parentheses).

Section 16, /Definite Assignment/
(<http://docs.oracle.com/javase/specs/jls/se7/html/jls-16.html>), states:
"Each local variable (§14.4) and every blank final field (§4.12.4,
§8.3.1.2) must have a definitely assigned value when any access of its
value occurs.
(...)
Such an assignment is defined to occur if and only if either the simple
name of the variable (or, for a field, its simple name qualified by
this) occurs on the left hand side of an assignment operator."

Note how assignment with a qualified this isn't mentioned.

Seems like a bit of a grey area to me.
 
S

Sven Köhler

Am 20.04.2013 19:02, schrieb lipska the kat:
I think that logically, Main.this.b refers to the enclosing *instance*
which implies that the class has been instantiated

"this" also refers to an instance - doesn't it?
And following your argument, I should not be able to use "this" in the
constructor.

I'm not saying, that the JLS makes a different between a mere "this" and
a construct of the form "Classname.this" and that this is essentially
the cause for the code not compiling. But I don't see the point of your
argument.


Regards,
Sven
 
M

markspace

Am 20.04.2013 19:02, schrieb lipska the kat:

"this" also refers to an instance - doesn't it?
And following your argument, I should not be able to use "this" in the
constructor.

Right, in a ctor, "this" refers to the object under construction. Ctors
are not static methods, they are instance methods that don't inherit or
participate in dynamic method name resolution.

The original question is kinda weird, Main.this.b feels like it should
be a static reference of some sort, or a reference to an enclosing
instance or something. It's a valid question, but also rather unnatural
to write and a corner case of the language.

I think the OP is asking for his class and students. I can't really
give a good answer why it does what it does. "It no work" is about all
I can say, and encourage the student to use "this.b" in cases like the
one cited.
 
A

Arne Vajhøj

Right, in a ctor, "this" refers to the object under construction. Ctors
are not static methods, they are instance methods that don't inherit or
participate in dynamic method name resolution.

The original question is kinda weird, Main.this.b feels like it should
be a static reference of some sort, or a reference to an enclosing
instance or something. It's a valid question, but also rather unnatural
to write and a corner case of the language.

I think the OP is asking for his class and students. I can't really
give a good answer why it does what it does. "It no work" is about all
I can say, and encourage the student to use "this.b" in cases like the
one cited.

No doubt about that.

But it is still puzzling about why the compilers give that error.

And it is both SUN javac and Eclipse JDT that barfs over it.

Arne
 
A

Arne Vajhøj

On 20/04/13 20:15, Arne Vajhøj wrote:
On 4/20/2013 12:02 PM, lipska the kat wrote:
On 20/04/13 14:11, Stefan Ram wrote:
Try to predict the behavior of the execution or compilation
of the following code!

public class Main
{ final int a; final int b;
Main(){ this.a = 0; Main.this.b = 0; }
public static void Main( final java.lang.String[] args )
{ new Main(); }}

(I made this observation while programming something else
using Oracle JDK 7, but I have not read the JLS about it yet.)

open-jdk6 and open-jdk7

I think that logically, Main.this.b refers to the enclosing *instance*
which implies that the class has been instantiated, final fields can
only be initialized once in a constructor so trying to (logically)
assign a value to a final variable after instantiation is illegal.

I think :-|

If you remove the final modifier from b then the code compiles, but
then
you know this already.

My understanding of the question is that it is why a work but not b
as this and Main.this should be the same.

Yes, this is what I understood.

I just don't think that >>this<< and >>Main.this<< are logically
equivalent.

this<< refers to the current instance,

Main.this<< refers to the (logically) enclosing instance which
implies that the >>Main.this.b<< assignment occurs after instantiation
which would be illegal which is why the compiler complains.

For the given code this and Main.this refer to the same object.

Ah yes, the old 'state the obvious to discredit the poster' technique
... weak (and incorrect, see below).

Instead of making incorrect observations try to come up with
a theory of your own. Here's an expansion of my theory

Java-7-openjdk, Eclipse Juno

The following code snippet gives 2 compile time errors

final int a; final int b;

public Main(){
this.a = 0;
Main.this.b = 0;
}

the errors are,

"the blank final field b may not have been initialized"
and
"the final field Main.b cannot be assigned"

This *implies* to me that this.b and Main.this.b are not *logically
equivalent*, this is what I said, nothing to do with whether
"For the given code this and Main.this refer to the same object." that
is entirely a fabrication of your own confused mind, in any case,

Nope.

The JVM agrees.

Try:

System.out.println(this==Main.this);
I
would never have used the work 'object' in this context, I would use the
word instance, not the same thing at all.

You may not have used the term, but since JLS use the term "object
equality", then that is not my problem.
If this and Main.this not equivalent then they must be different, now
all we need to figure out is what the difference is.

The logic that:

the compiler must be correct => different handling by compiler most mean
that they are different => compiler is right

is a circular logic.
I say that the difference is that the construct Main.b *logically*
refers to a concrete instance of Main which implies that Main has been
instantiated which means that you are trying to initialize a blank final
variable outside the class constructor which is illegal.

The exact same logic could just as well be applied to this, so it
does not hold water.

Arne
 
S

Sven Köhler

Not sure what you mean here as Eclipse can be configured to use
different compilers

Eclipse only has one compiler. It's specially written by IBM for
Eclipse, and it's not based on javac as far as I know.
independently of the version of Java used to run the
application (Eclipse)

I configured Eclipse to compile against

java-7-openjdk
and, separately
java version 1.6.0_35

But each time, you're using Eclipse's compiler, and not the javac of the
JDK.


Regards,
Sven
 
A

Arne Vajhøj

On 28/04/13 11:34, Chris Uppal wrote:

[snip]
I'm guessing (and I admit that I can find no other supporting
evidence) that
this is a bug in the compiler where code that is written on the
assumption that
"C" above must be a strictly enclosing class. In those case the
(equivalent)
code would obviously be incorrect (and that goes for the blank-final
example
too). In particular I suspect that its something going squiffy in the
contorted logic that allows nested classes to refer to private fields
of the
[not actually] "enclosing" class at runtime: that horrible stuff that
is added
to circumvent the JVMs own checking.

But I may as well admit that one piece of evidence against my guess is
that
both javac and Eclipse "fail" in the same way.

Not sure what you mean here as Eclipse can be configured to use
different compilers independently of the version of Java used to run the
application (Eclipse)

I configured Eclipse to compile against

java-7-openjdk
and, separately
java version 1.6.0_35

and both times came up with the same error

That is the runtime enviroment.

Eclipse uses a special incremental compiler no matter what
runtime environment.

I believe it is called ecj.

And it is actually used in a few other products like
newer versions of Tomcat.

Arne
 
A

Arne Vajhøj

Arne said:
This *implies* to me that this.b and Main.this.b are not *logically
equivalent*, this is what I said, nothing to do with whether
[obnoxious stuff elided]

Nope.

The JVM agrees.

Try:

System.out.println(this==Main.this);

But that proves nothing, doesn't even indicate anything.

It shows that it is the same object.
It's commonplace for
two independent identifiers to refer to the same object. And those two
different forms of reference may have different rules (consider using protected
access via "this" verses an independent reference to the same object).

Nothing unusual in that a.b and c.d.f.g.h.j refers to same object.

And if the question is about accessibility then obviously the
path to the object is relevant.

But should the path used for access be relevant for whether something
in the object is definite assigned or definite unassigned?
I'm guessing (and I admit that I can find no other supporting evidence) that
this is a bug in the compiler where code that is written on the assumption that
"C" above must be a strictly enclosing class. In those case the (equivalent)
code would obviously be incorrect (and that goes for the blank-final example
too). In particular I suspect that its something going squiffy in the
contorted logic that allows nested classes to refer to private fields of the
[not actually] "enclosing" class at runtime: that horrible stuff that is added
to circumvent the JVMs own checking.
Yes.

But I may as well admit that one piece of evidence against my guess is that
both javac and Eclipse "fail" in the same way.

Yes.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
SterlingLa
Top