*
The moose likes Programmer Certification (SCJP/OCPJP) and the fly likes final variable declared in a loop Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Certification » Programmer Certification (SCJP/OCPJP)
Bookmark "final variable declared in a loop" Watch "final variable declared in a loop" New topic
Author

final variable declared in a loop

Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391

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?
William Brogden
Author and all-around good cowpoke
Rancher

Joined: Mar 22, 2000
Posts: 12761
    
    5
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
Corey McGlone
Ranch Hand

Joined: Dec 20, 2001
Posts: 3271
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


SCJP Tipline, etc.
Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391
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

Joined: Dec 20, 2001
Posts: 3271
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

Joined: Mar 05, 2003
Posts: 1391
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

Joined: Dec 20, 2001
Posts: 3271
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

Joined: Dec 20, 2001
Posts: 3271
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
Jessica Sant
Sheriff

Joined: Oct 17, 2001
Posts: 4313

Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391
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
Rancher

Joined: Mar 22, 2000
Posts: 12761
    
    5
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

Joined: Mar 05, 2003
Posts: 1391
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

Joined: Mar 05, 2003
Posts: 1391
(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
Rancher

Joined: Mar 22, 2000
Posts: 12761
    
    5
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
Barkat Mardhani
Ranch Hand

Joined: Aug 05, 2002
Posts: 787
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 ]
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
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 ]
Jose Botella
Ranch Hand

Joined: Jul 03, 2001
Posts: 2120
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 ]

SCJP2. Please Indent your code using UBB Code
Jose Botella
Ranch Hand

Joined: Jul 03, 2001
Posts: 2120
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.
Lih Chang
Greenhorn

Joined: Mar 21, 2003
Posts: 19
Originally posted by Botella
[ April 10, 2003: Message edited by: Thomas Paul ]
Jose Botella
Ranch Hand

Joined: Jul 03, 2001
Posts: 2120
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 ]
Thomas Paul
mister krabs
Ranch Hand

Joined: May 05, 2000
Posts: 13974
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.


Associate Instructor - Hofstra University
Amazon Top 750 reviewer - Blog - Unresolved References - Book Review Blog
William Brogden
Author and all-around good cowpoke
Rancher

Joined: Mar 22, 2000
Posts: 12761
    
    5
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
Ranch Hand

Joined: May 05, 2000
Posts: 13974
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
Ranch Hand

Joined: May 05, 2000
Posts: 13974
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
Ranch Hand

Joined: May 05, 2000
Posts: 13974
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
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
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
Rancher

Joined: Mar 22, 2000
Posts: 12761
    
    5
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

Joined: Jul 03, 2001
Posts: 2120
"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
Ranch Hand

Joined: May 05, 2000
Posts: 13974
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

Joined: Aug 05, 2002
Posts: 787
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

Joined: Mar 05, 2003
Posts: 1391
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
Rancher

Joined: Mar 22, 2000
Posts: 12761
    
    5
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
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: final variable declared in a loop
 
Similar Threads
Traps to be aware of in any SCJP test !!!!! :)
Sun Cirtification
Final keyword???
case doubt
regarding blank final