• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

final variable declared in a loop

 
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

compiler error: �cannot assign a value to final variable x�
If I were to tell you I am getting a compiler error, you might explain to me that final variables can only be assigned to once.
But if I were to tell you I am *not* getting a compiler error, you might explain that each time around the loop is a new variable.
The point is people seem to find an explanation to fit the result.
If I were to tell you I *am* getting a compiler error, I wish you would say, But that is impossible. That cannot be so, because...
I don�t want to seek an explanation in the compiled byte codes. The person that wrote the compiler had to first understand what it means for final variables to be declared in loops.
My question is why can a final variable declared in a loop be assigned to once each time around the loop? Why is that consistent with the JLS?
 
Author and all-around good cowpoke
Posts: 13078
6
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You should not expect any Java compiler to be capable of enforcing 100% compliance with the JLS. For example, back in Java 1.2, you could compile a class with the synchronized modifier (which was of course meaningless.)
Compilers have gotten better about catching this sort of thing, but the ultimate reference is always the JLS.
Bill
 
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Marlene Miller:
My question is why can a final variable declared in a loop be assigned to once each time around the loop? Why is that consistent with the JLS?


Well, Marlene, the JLS doesn't exactly come forth in a single statement taht says that final variables can be declared and assigned within loops - you have to put a couple pieces together. First, let's look at the section on final variables, §4.5.4 final Variables:


A variable can be declared final. A final variable may only be assigned to once. It is a compile time error if a final variable is assigned to unless it is definitely unassigned (�16) immediately prior to the assignment.


So, it would seem as if we'd get a compile-time error every time we executed that loop (except the first time), because we'd be reassigning a final variable. But, if we put that together with the portion of the JLS that discusses scope of a declaration, §6.3 Scope of a Declaration:


The scope of a local variable declaration in a block (�14.4.2) is the rest of the block in which the declaration appears...


Therefore, when the block of code within the loop finishes and we restart the loop, that local variable (even though it's final) ceases to exist. Now, when we enter the loop the next time, we have created a brand new local, final variable that we can assign to.
Hence, no compiler error.
I don't know if this is truly what you were looking for, Marlene, but that's my best crack at it for now.
Corey
 
Marlene Miller
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you Corey. Your answer makes sense. It was presented very clearly.
(1) Now, to repeat in a slightly different way a part of what you have said...
A while statement has the form
while (Expression) Statement
The scope of the variable x is a region of code within the �Statement�. After the �Statement� is executed, the �Expression� is evaluated again. At this point, the variable is out of scope.
Is that correct?
(2) Suppose we say �scope� is the textual region of the program in which a binding is active. Could a binding be not active but still exists (such as static local variables in C)?
If so, in my example, would we have to assume every time the virtual machine exits the scope of the variable, the binding is not only deactivated but also destroyed?
(I think I am wandering outside the scope of what I understand without a proper education.)
 
Corey McGlone
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Marlene Miller:
The scope of the variable x is a region of code within the �Statement�. After the �Statement� is executed, the �Expression� is evaluated again. At this point, the variable is out of scope.
Is that correct?


Yes. Exactly.


(2) Suppose we say �scope� is the textual region of the program in which a binding is active. Could a binding be not active but still exists (such as static local variables in C)?
If so, in my example, would we have to assume every time the virtual machine exits the scope of the variable, the binding is not only deactivated but also destroyed?
(I think I am wandering outside the scope of what I understand without a proper education.)


The inner workings of the binding process behind local variables is a bit beyond me. I could tell you what I think but, as I don't really know the answer for sure, I'll just cop out and not say anything at all (in other words, I'm wussing out so that some smarter rancher can answer this ). This is really going beyond the language itself and delving into the JVM. You might want to take a look here, but I don't know if you'll really find what you're after.
Corey
 
Marlene Miller
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you Corey.
It's an interesting topic, but in the real world I suppose a zealous programmer's manager would call pursuing this issue "creeping scope".
 
Corey McGlone
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Marlene Miller:
It's an interesting topic, but in the real world I suppose a zealous programmer's manager would call pursuing this issue "creeping scope".


Not to mention, "fodder for another forum."
 
Corey McGlone
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Okay, I couldn't resist - a little more info before I let this topic die...
From the VM Spec, §3.6.1 Local Variables:


Each frame (�3.6) contains an array of variables known as its local variables. The length of the local variable array of a frame is determined at compile time...


As the size of the array containing local variables is known at compile time, there can be only 1 entry for the final variable within the loop (as it's unknown how many times a loop may execute). Based on that, I would say that the binding must be destroyed when the variable goes out of scope because the variable itself (within the JVM Frame) still exists within the local variable array. Therefore, in order to keep the final variable from being assigned to a second time, the binding, from one iteration of the loop to the second, would have to be destroyed.
Now, this is largely speculation, but that's my best guess. Of course, don't expect anything like this on the exam - I just thought it was interesting. :roll:
Another thing to keep in mind is that the JVM Spec puts forward specific rules that a JVM must comply with but, how it implements those rules is really up to the implementor of the JVM and, in many cases, some leeway is given in order to ease implementation.
Ok, so now I'm feeling a little too interested in awfully geeky things.
Corey
 
Sheriff
Posts: 4313
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
 
Marlene Miller
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I have a book called Programming Language Pragmatics by Michael Scott. Maybe some day I will have a chance to read it. Chapter 3 is 60 pages on Names, Scopes, and Bindings. They talk about static and dynamic binding. Nothing leaps out of the pages about loops. But if I understood that stuff, maybe the final variable loop puzzle would be obvious.
I don�t find anything in the JVM about final local variables. I thought there might be at least some kind of flag. But no. It appears the compiler does whatever it wants to achieve the appearance of the intended effect.
 
William Brogden
Author and all-around good cowpoke
Posts: 13078
6
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Lets review exactly why there is such a thing as a final local variable. When inner classes were added to Java, it was realized that declaring a class inside a method creates a real problem when you want that class to make use of a local variable - either a calling parameter or a variable declared inside the method.
The storage for such a variable is in the stack frame of the Thread that calls the method and thus will be meaningless once the method exits. Since the object created from the local class could live long after the Thread exits, you have a serious potential problem.
This was solved by creating a new use for "final" - the compiler handles allocating space for these local variables differently so they are not lost when the method exits.
Exactly what this implies for your example with the loop is an interesting question! but for the exam you need to remember that the only local variable a local inner class can access is one labeled final.
Bill
 
Marlene Miller
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you Bill. Back to reality.
(Well, maybe someone wants to create a sequence of anonymous classes with a for loop. Just kidding.)
On that topic, I remember reading in The Java Programming Language �If needed, you can copy a non-final variable into a final one which is subsequently accessed by the local inner class.�

Since I could move the non-final variable to a final variable just before instantiating the anonymous class, why doesn�t the compiler just do it for me without my declaring a final variable y?
 
Marlene Miller
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
(Granted, these issues will not show up on the exam. But I figure, the better I understand, the less I will have to remember for the exam and the more confidence I will have in my answers.)
 
William Brogden
Author and all-around good cowpoke
Posts: 13078
6
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
With respect to "why doesn't the compiler do this for me" - I suspect the designers are struggling to keep the compiler as simple as possible so that they can concentrate on performance.
From a programmer point of view, I'm glad that the compiler makes you declare things - that keeps the code clear (at the expense of extra typing.) It will pay off later when somebody else has to maintain the code
Bill
 
Ranch Hand
Posts: 787
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Quote from Bill's post:

Lets review exactly why there is such a thing as a final local variable. When inner classes were added to Java, it was realized that declaring a class inside a method creates a real problem when you want that class to make use of a local variable - either a calling parameter or a variable declared inside the method.
The storage for such a variable is in the stack frame of the Thread that calls the method and thus will be meaningless once the method exits. Since the object created from the local class could live long after the Thread exits, you have a serious potential problem.
[B]This was solved by creating a new use for "final" - the compiler handles allocating space for these local variables differently so they are not lost when the method exits.[B]
Exactly what this implies for your example with the loop is an interesting question! but for the exam you need to remember that the only local variable a local inner class can access is one labeled final.
Bill


If what is stated in bold is true, Why do I get compile error in following:

[ April 09, 2003: Message edited by: Barkat Mardhani ]


[ April 09, 2003: Message edited by: Barkat Mardhani ]

 
author
Posts: 3252
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by William Brogden:
[...]The storage for [a local] variable is in the stack frame of the Thread that calls the method and thus will be meaningless once the method exits. Since the object created from the local class could live long after the Thread exits, you have a serious potential problem.
This was solved by creating a new use for "final" - the compiler handles allocating space for these local variables differently so they are not lost when the method exits.

My understanding is that the variable is actually allocated on the stack frame, just like a non-final local variable -- but that, when you create an inner class referencing this variable, a copy of the variable is included as an (implicit) instance field of the inner class. This is why inner classes can use the variable even after it has gone out of scope: they carry their own private copy with them. And it is also explains why these variables must be final: otherwise, the copy could get "out of sync" with the real variable and the illusion that you are accessing a method-local variable could no longer be maintained.
So "final" did not really do something fundamentally new itself, but it made something new possible: transparently giving inner classes implicit copies of the variable in the knowledge that the original would never change anyway.
Please note that I have been known to be wrong before
- Peter
[ April 09, 2003: Message edited by: Peter den Haan ]
 
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Barkat, what he means is showed in this example:

_______________________________________________
Marlene, you might find interesting that the compiler replaces the ocurrences of final variables with the proper value. If such value cannot be assigned built-in in the certain special bytecodes, it is loaded from the contant pool of the class where the final variable was declared.

Final variables are placed in the constant pool of the class declaring them.
-- I have modified the previous example that did not showed what I meant, this is ok--
[ April 09, 2003: Message edited by: Jose Botella ]
[ April 09, 2003: Message edited by: Jose Botella ]
 
Jose Botella
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hey Peter, as almost always , you are right.
This is the method FinalVariableScope$1.method() parsed with javap:

bipush 10 is the copy of the value.
 
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Originally posted by Botella
[ April 10, 2003: Message edited by: Thomas Paul ]
 
Jose Botella
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You are absolutely right Lih, the compiler only can do that if the variable is assigned a value known at compile time (JLS 15.28).
For instance:

In line 18 the value 67788 is loaded from the entry #5 in the constant pool. However line 11 provides the content of the local variable 2 to the method println
[ April 09, 2003: Message edited by: Jose Botella ]
 
mister krabs
Posts: 13974
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In this case, Peter is correct and Bill is mistaken. Although there has been some confusion over this (at least some of the confusion looks deliberately created by certain people at Sun), local variables are not accessed directly by the inner class but are copied and given to the inner class in the same way that parameters are passed to methods. There is no reason that local variables used in an inner class must be final except to avoid confusion.
 
William Brogden
Author and all-around good cowpoke
Posts: 13078
6
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
So how is creating an invisible copy of the final variable that is carried by the object created by the inner class different from what I said?
Bill
 
Thomas Paul
mister krabs
Posts: 13974
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What you said is that when the surrounding method expires the local variable would be lost. This isn't true since the inner class is actually a completely different class once it is compiled. The JVM doesn't know anything about inner classes. (This was done for binary compatibility.) Only the compiler does. Local variables are passed to inner classes the same way that local variables are passed to any method. You said this: "The storage for such a variable is in the stack frame of the Thread that calls the method and thus will be meaningless once the method exits" but since a copy has been made and passed to the inner class, this doesn't matter because only the original variable would be meaningless, not the copy.
 
Thomas Paul
mister krabs
Posts: 13974
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Not all final variables can be inlined. Any final variable value from the return of a method invocation will not be inlined. For example:
final long time = System.currentTimeMillis();
 
Thomas Paul
mister krabs
Posts: 13974
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This is from another thread but I think it is worth repeating:
This what I am talking about:

If this would compile (it doesn't because x isn't final) it would print:
0
0
And that is why x must be final.
 
Peter den Haan
author
Posts: 3252
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by William Brogden:
So how is creating an invisible copy of the final variable that is carried by the object created by the inner class different from what I said?

It is probably not different from what you said, but it is different from what I read. No, I'm not trying to be clever here what I mean to say is that the mental image I got from your description didn't match my understanding of how it works. That image doesn't necessarily match the one you wanted to convey.
In particular, by first relating how local variables are allocated in the stack frame, and then proceeding to say that final variables are allocated differently, it almost seemed as if they lived completely outside the stack frame.
- Peter
[ April 10, 2003: Message edited by: Peter den Haan ]
 
William Brogden
Author and all-around good cowpoke
Posts: 13078
6
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Lets see if we can come up with a clearer
statement of how Java solves the problem of anonymous inner class access to enclosing class variables.
When it encounters a inner class declaration inside a method, the compiler creates a no-args constructor that does the following:
1. create an instance variable that holds a reference
to the enclosing object that can be used to give
the inner class instance access to all static and
instance variable of the enclosing object.
2. create an instance variable containing a copy of
all local variables that the instance references.
These variables must be declared with a special
usage of the "final" modifier to emphasize that
once the instance of the inner class gets the
value, it can't be changed.
--- note - this is not

given to the inner class in the same way that parameters are passed to methods.


instead it is creation of an instance variable that contains a copy of the local variable as it existed when the object was created.
Bill
 
Jose Botella
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
"javap -c FinalVariableScope$1" shows what they are talking about:

The field val$local_variable, of the instance of the inner class, is created automatically by the compiler (a synthetic one) to hold the copy of the variable. This is so because its value is not known at compile time.
 
Thomas Paul
mister krabs
Posts: 13974
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Back to the original question: Corey nailed it. In fact Corey's explanation expalins why there is no performance penalty in code block 2 as compared to code block 1:


There is no performance penalty whatsoever for declaring local variables in a loop. Doing so makes them local to the loop, which they should be if they are not used outside of the loop.
[ April 10, 2003: Message edited by: Thomas Paul ]
 
Barkat Mardhani
Ranch Hand
Posts: 787
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Going back to original question by Marlene. Her code:

compiles and runs fine with 1.3 compiler. I saw a similar example code in Java in a Nutshell by David Flanagan (3rd edition) on page 127 that I asume also runs fine. So my question is if this compiler error is version dependent what is expected in the exam?
Thanks
Barkat
[ April 10, 2003: Message edited by: Barkat Mardhani ]
[ April 10, 2003: Message edited by: Barkat Mardhani ]
 
Marlene Miller
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you to everyone for your generous and deep thoughts related (and not related) to my question.
As far as I know, there is no compiler error.
[ April 10, 2003: Message edited by: Marlene Miller ]
 
William Brogden
Author and all-around good cowpoke
Posts: 13078
6
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I think it has to do with the special meaning assigned to final in this local variable context not having the same connotation as it would with an instance variable. In the following example, the final int x gets a new value on every pass through the loop. I think the interpretation is that inside the scope of the variable, once it has gotten a value, you can't change it.

Bill
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic