# How to illustrate scope problem when creating variables inside if statements in Java

One of the problems that my students will stumble upon every year is trying to create or initialize variables within an if/else block. Why, oh why, can't they perform an operation like this?

if (someBooleanCondition){
int x = 7;
} else {
int x = 0;
}
System.out.println(x);


After all, they reason that x has been created and initialized no matter what. This year, I discovered a nice way of explaining why this operation does not work. I will be posting my answer below, and I am also curious to see if others have different explanations that they use with their students (or corrections to mine).

• [I have not tried this.] When showing how variables work, using the box metaphor, burn the box(and its content) at the end of its block. (you may want to do this out-side.) – ctrl-alt-delor May 31 '17 at 7:40
• Suggested better title “How to illustrate scope problem when creating variables inside if statements.” — with current title my first thought was “Yes you can”. – ctrl-alt-delor May 31 '17 at 7:42
• Its certainly a scope problem, and there's no problem with initialising (except for only initialising in one path). – Sean Houlihane May 31 '17 at 9:45
• That's a much better title. Thanks, @richard. – Ben I. May 31 '17 at 10:29
• Scope of variables, and distinction between declaration and initialization. Anyway students stumble every year, because they are learning. – Michel Billaud Sep 22 '19 at 8:49

I like to use an analogy from Finding Nemo. I tell them their programming language has the same problem Dory has - short-term memory loss. When a variable is declared within a block, Java will forget about the variable (just like Dory) after reaching the end of the the block. So a block declares the "scope" of Dory's short term memory.

I've been concerned that students would think that the variables assigned in a block would lose their value after the block has ended, but I've never run into that problem for some reason.

What's interesting about your example is that it won't even compile without the print statement! Java doesn't allow you to have a single declaration statement in an if or loop.

• I don't get what you mean in the 2nd paragraph. Do you mean that the variable still exist but have a value of undefined? – ctrl-alt-delor May 31 '17 at 7:32
• I like it. I don't understand it, since I have no context for Dory (never watched Finding Nemo). That's part of the problem, finding context that matches what the students know. – Gypsy Spellweaver Jun 1 '17 at 3:55
• Here's a scene from the movie that you could show for reference: youtube.com/watch?v=tESffhWs8l0 – Matthew Fahrenbacher Jun 1 '17 at 18:24

I explain this with a saying:

What happens in the block stays in the block

Now, this isn't exactly how it works, but the idea is that the students remember that what they create in a block, is accessible only inside the block.

So:

if(shouldGoIntoBlock){
int x=10;//created in the block
else{
int x=-7;//created in the block
}
System.out.println("printed outside of blocks: "+x);


And they see in eclipse that the last print errors in compile time. That shows them that what's created in the block stays in the block.

Next, I show them that there will also be an error if we define x before the if-else block, but the last line won't error. So they see that order of creation matters. Afterwards, I show them that creating x after the if-else block and before the last print, then there are no errors.

The vast majority of the students understand the idea this way.

They don't learn the stack segment of the computer at that time, but they see that order matters, and that makes learning about the stack easier for them when they learn it later in the year.

I teach my students a bit about the stack as part of the very first lesson of the year. As a result, they are aware coming in that primitive variables are stored next to one another in the stack during runtime, and that the names of the primitive variables that we use in our code are removed by the compiler, and replaced with memory locations. They are also aware by this time that the stack is populated in the order in which variables are declared. Thus, I show them the following code, and ask a simple question:

if (someBooleanCondition){
int v = 18;
int x = 7;
} else {
int x = 0;
int v = o;
}


If we now wanted to run System.out.println(x), it is true that x has a value, but what is its location? If someBooleanCondition is true, x will be at the higher of the two addresses, whereas if it is false, x will be at the lower of the two addresses How would the compiler know where to direct System.out.println to find x?

Thus, the scope of variables declared during if statements must be local to that if statement, and cannot be used outside of it.

Java, like C/C++ has block scope. When you create a variable in a block, the stack pointer moves to make room for it. When the block ends, the stack pointer moves back. This makes the variable inaccessible. It will be overwritten the next time the stack pointer moves over it.

Python and JavaScript have function scope. Note, however that in ECMA 6, the let construct gives variables block scope.

You should be able to copy/paste block of codes that does not use other variables. But in your examples what if you want to copy/paste that to a code that already declared x? It would not work

String x = "Ben I.";
... a lot of code
...
...
if (someBooleanCondition){
int x = 7;
} else {
int x = 0;
}
System.out.println(x);


In that case you want to print Ben I. In block scope very often you need to use temporary variables to help you in some calculations and if you declared them in block then you want them to be cleared from stack when you get out of the block.

Something that might be helpful is using computers. Files created on the school computer in the classroom don't exist anywhere else. The file can be copied somewhere else, just like passing it back from a function copies the data, not the variable, to the caller.

A second option is just to use the directory structure of the computer itself. Creating /home/mine/Documents/computer_class/project_1/notes.txt will show file not found if you try to access /home/mine/Documents/computer_class/notes.txt. [Or for Windows C:\Users\mine\Documents\Computer Class\Project 1\notes.txt can't be edited using C:\Users\mine\Documents\Computer Class\notes.txt.]

One thing to bear in mind is that not all languages enforce variables to be scoped at that granular of a level, or at all. In addition, how that scope is enforced, or implemented, can also be language dependent. If the language in use has been dissected by the class, then using its internal process can explain why it happens in that case.

Unless the students will always be using that language, even after school, I think it's important to also make them aware that those rules may, or may not, apply, and that when they don't apply side effects can become an issue. In some cases the value isn't undefined, as in non-existent, rather it can be undetermined, as in something is there, but not sure what.

• If we were to use this analogy, how would we deal with variables declared prior to the if, which are accessible inside of it, or instance variables? – Ben I. Jun 5 '17 at 2:18
• Depends on which version. For Google Drive, the local computer (inside if has access to Google Drive (outside if) but Google Drive has no access to local computer. For the file system version emulate the if block's access with a symlink/shortcut. The file (variable) still belongs to the higher level, but the inner block has been granted access (probably by reference, either to the outer block's scope, or to the data itself). – Gypsy Spellweaver Jun 5 '17 at 2:24

Another benefit of block-level scope is that because variables defined in a block go out of scope at the end of that block, their values are then eligible for garbage collection (assuming no other variables point to them).

Expand your example to use some really big object that takes up a lot of memory:

if (someBooleanCondition){
ReallyBigObject rbo = getReallyBigObject();
rbo.doSomeProcessing();
} else {
ReallyBigObject rbo = getOtherReallyBigObject();
rbo.doSomeOtherProcessing();
}

//rbo is out of scope and can be garbage collected!


With the way Java works, the really big object goes out of scope at the end of the if or else block it's declared in. That means it can be garbage collected, and that's awesome because we don't have to worry about it anymore!

It's possible to have function-level scope (like JavaScript), so the students' intuition isn't wrong. It's just that Java chose a set of rules to allow garbage collection to happen sooner rather than later.

But as a result, this also means that you can't use a variable outside of its scope.