tags:

views:

3447

answers:

10

Was there any reason why the designers of Java felt that local variables should not be given a default value? Seriously, if instance variables can be given a default value, then why can't we do the same for local variables?

And it also leads to problems as explained in this comment to a blog post...

+1  A: 

I think the primary purpose was to maintain similarity with C/C++. However the compiler detects and warns you about using uninitialized variables which will reduce the problem to a minimal point. From a performance perspective, it's a little faster to let you declare uninitialized variables since the compiler will not have to write an assignment statement, even if you overwrite the value of the variable in the next statement.

Mehrdad Afshari
Arguably, the compiler could determine whether you always assign to the variable before doing anything with it, and suppress an automatic default value assignment in such a case. If the compiler can't determine whether an assignment happens before access, it would generate the default assignment.
Greg Hewgill
Yes, but one might argue that it lets the programmer know if he or she has left the variable uninitialized by mistake.
Mehrdad Afshari
The compiler could do that in either case too. :) Personally, I would prefer that the compiler treats an uninitialised variable as an error. It means I might have made a mistake somewhere.
Greg Hewgill
I'm not a Java guy, but I like the C# way of handling it. The difference is in that case, the compiler had to issue a warning, which might make you get a couple hundred of warnings for your correct program ;)
Mehrdad Afshari
Does it warn for the member variables too?
Adeel Ansari
Nope, member variables will be initialized both in Java and C# by the compiler, if you don't specify a thing.
Mehrdad Afshari
+6  A: 

Local variables are declared mostly to do some calculation.So its the programmer decision to give the value to the variable and it should not take default value .If programmer by mistake did not initialize a local variable and it take default value then the output go wrong.so locale variable will ask programmer to initialize before he use the variable to avoid making mistake.

Warrior
+3  A: 

Notice that the final instance/member variables don't get initialized by default. Because those are final and can't be changed in the program afterward. Thats the reason that Java doesn't give any default value for them and force the programmer to initialize it. On the other hand, the non-final member variables can be referred by anyone with access to the class and these variables; hence compiler cannot let them remain un-initialized. This is not the case with local variables and compiler knows when its getting used and whether it has been initialized or not. The scope of local variables are much smaller. Hence, forcing programmer to initialize the variable make sense.

Adeel Ansari
+8  A: 

The "problem" you link to seems to be describing this situation:

SomeObject so;
try {
  // Do some work here ...
  so = new SomeObject();
  so.DoUsefulThings();
} finally {
  so.CleanUp(); // Compiler error here
}

The commenter's complaint is that the compiler balks at the line in the finally section, claiming that so might be uninitialized. The comment then mentions another way of writing the code, probably something like this:

// Do some work here ...
SomeObject so = new SomeObject();
try {
  so.DoUsefulThings();
} finally {
  so.CleanUp();
}

The commenter is unhappy with that solution because the compiler then says that the code "must be within a try." I guess that means some of the code may raise an exception that isn't handled anymore. I'm not sure. Neither version of my code handles any exceptions, so anything exception-related in the first version should work the same in the second.

Anyway, this second version of code is the correct way to write it. In the first version, the compiler's error message was correct. The so variable might be uninitialized. In particular, if the SomeObject constructor fails, so will not be initialized, and so it will be an error to attempt to call so.CleanUp. Always enter the try section after you have acquired the resource that the finally section finalizes.

The try-finally block after the so initialization is there only to protect the SomeObject instance, to make sure it gets cleaned up no matter what else happens. If there are other things that need to run, but they aren't related to whether the SomeObject instance was property allocated, then they should go in another try-finally block, probably one that wraps the one I've shown.

Requiring variables to be assigned manually before use does not lead to real problems. It only leads to minor hassles, but your code will be better for it. You'll have variables with more limited scope, and try-finally blocks that don't try to protect too much.

If local variables had default values, then so in the first example would have been null. That wouldn't really have solved anything. Instead of getting a compile-time error in the finally block, you'd have a NullPointerException lurking there that might hide whatever other exception could occur in the "Do some work here" section of the code. (Or do exceptions in finally sections automatically chain to the previous exception? I don't remember. Even so, you'd have an extra exception in the way of the real one.)

Rob Kennedy
why not just have anif(so!=null)...in the finally block?
izb
that will still cause the compiler warning/error - i dont think the compiler understands that if check (but i m just doing this off memory, not tested).
Chii
I'd put just SomeObject so = null before try and put null check to finally clause. This way there will be no compiler warnings.
Juha Syrjälä
Why complicate things? Write the try-finally block this way, and you KNOW the variable has a valid value. No null-checking required.
Rob Kennedy
Rob, your example "new SomeObject()" is simple and no exceptions should be generated there, but if the call can generate exceptions then it would be better to have it occur inside the try-block so that it can be handled.
sjbotha
You could always just use an additional try-catch block around the whole thing.
Outlaw Programmer
First, Sjbotha, exceptions *can* be generated there. We could run out of memory, or, more likely, the SomeObject constructor could throw its own exceptions. We have no idea what it does.
Rob Kennedy
Second, it would NOT be better to have the constructor call inside that try block. That's a try-finally block, which does NOTHING to handle exceptions. If an exception occurred, we'd be calling CleanUp on an uninitialized or null variable, and we'd be back to the same state as in my first code block
Rob Kennedy
A: 

Eclipse even gives you warnings of uninitialized variables, so it becomes quite obvious anyway. Personally I think it's a good thing that this is the default behaviour, otherwise your application may use unexpected values, and instead of the compiler throwing an error it won't do anything (but perhaps give a warning) and then you'll be scratching your head as to why certain things don't quite behave the way they should.

Kezzer
A: 

It is more efficient not to initialize variables, and in the case of local variables it is safe to do so, because initialization can be tracked by the compiler.

In cases where you need a variable to be initialized you can always do it yourself, so it is not a problem.

starblue
+4  A: 

Moreover, in the example below, an exception may have been thrown inside the SomeObject construction, in which case the 'so' variable would be null and the call to CleanUp will throw a NullPointerException

SomeObject so;
try {
  // Do some work here ...
  so = new SomeObject();
  so.DoUsefulThings();
} finally {
  so.CleanUp(); // Compiler error here
}

What I tend to do is this:

SomeObject so = null;
try {
  // Do some work here ...
  so = new SomeObject();
  so.DoUsefulThings();
} finally {
  if (so != null) {
     so.CleanUp(); // safe
  }
}
Electric Monk
That's just pointlessly messy.
Tom Hawtin - tackline
What would you rather do?
Electric Monk
A: 

Same question: http://stackoverflow.com/questions/268814/uninitialized-variables-and-members-in-java

Yuval A
Sorry about that... this question didn't popup when I was typing in the question.. however, I guess there's a difference between the two questions... I want to know why the designers of Java *designed* it this way, whereas the question you pointed to does not ask that...
Shivasubramanian A
A: 

The local variables are stored on a stack, but instance variables are stored on the heap, so there are some chances that a previous value on the stack will be read instead of a default value as happens in the heap. For that reason the jvm doesn't allow to use a local variable without initialize it.

David Santamaria
Flat out wrong...all Java non-primitives are stored in the heap regardless of when and how they are constructed
gshauger
+1  A: 

(It may seem strange to post a new answer so long after the question, but a duplicate came up.)

For me, the reason comes down to this this: The purpose of local variables is different than the purpose of instance variables. Local variables are there to be used as part of a calculation; instance variables are there to contain state. If you use a local variable without assigning it a value, that's almost certainly a logic error.

That said, I could totally get behind requiring that instance variables were always explicitly initialized; the error would occur on any constructor where the result allows an uninitialized instance variable (e.g., not initialized at declaration and not in the constructor). But that's not the decision Gosling, et. al., took in the early 90's, so here we are. (And I'm not saying they made the wrong call.)

I could not get behind defaulting local variables, though. Yes, we shouldn't rely on compilers to double-check our logic, and one doesn't, but it's still handy when the compiler catches one out. :-)

T.J. Crowder