| Home | Resources | Papers | Essays | Short Fiction | About |

Variables

Table of Contents

Introduction

Think back to your first time encountering an algebraic formula; say something as simple as y = x + 1. You likely learned that x is an unknown value, or at least a value which isn't known the moment you glanced at the formula. x is a stand-in, a signifier, a symbol, a name, i.e., something that represents the presence of some magnitude. x is a variable. The value attached to x is subject to change. The potential value attached to it is external to the formula itself.

Variables in Programming Languages

Variables within programming languages satisfy a similar, although not identical, position to variables within algebraic formulas1. Variables are names for data stored in the computer. When we write x = 1 we are saying that x is a name which represents the computational object 1 which exists somewhere within the hardware of the machine running the program. As the name suggests, variables can change values. For example, we can write x = x + 1 which increments the values of x.

Scope

All identifiers, including variable names, will have a scope associated with them. Scope has two facets in C: (1) the lexical scope; (2) the linkage scope. Here, we focus on the lexical scope which refers to "the region of the program text within which the identifier's characteristics are understood"2. An example should be instructive:

 1: public class Scope {
 2:     // Block 0, "Global" scope
 3:     static int g = 4;
 4: 
 5:     public static void main(String[] args) {
 6:         // Block 1, Outer main method
 7:         int x = 1;
 8:         {
 9:             // Block 2, Inner main method
10:             int y = 2;
11:             {
12:                 // Block 3, Innermost main method
13:                 int z = 3;
14:             }
15:         }
16:     }
17: }

Listing 4 shows a Java program which defines 4 int type variables: g, x, y, z, each one within a different code block. In Java, braces, "{}", indicate the starting and closing of a code block, i.e., a collection of statements (you can think of statements as the sentences of programming languages). These blocks are the arbiter's of a variable's lexical scope (hereon referred to simply as "scope"). When a variable is defined in a given block, it can be "seen" by all statements/expressions within the same block as well as interior blocks. For example, g is visible at Block levels 0, 1, 2, and 3, despite it only being declared in Block 0. We call Block 0 the global scope—this refers to anything declared outside of a function block (such as the function main). Furthermore, x is visible at Block levels 1, 2, and 3, but not at Block 0. Every time a block is exited, all of the names defined therein are forgotten. To further emphasize this I will update Listing 4 so that z is referenced in Block 1 after it has been defined in Block 3:

 1: public class Scope {
 2:   // Block 0, Global scope
 3:   static int g = 4;
 4: 
 5:   public static void main(String[] args) {
 6:     // Block 1, Outer main method
 7:     int x = 1;
 8:     {
 9:       // Block 2, Inner main method
10:       int y = 2;
11:       {
12:         // Block 3, Innermost main method
13:         int z = 3;
14:       }
15:     }
16:     x = z + 1;
17:   }
18: }

When I try to compile this code, I get the following error:

josephraskind@stargazer:/tmp/scope$ javac Scope.java 
Scope.java:16: error: cannot find symbol
        x = z + 1;
            ^
  symbol:   variable z
  location: class Scope
1 error

Why does the compiler say that z cannot be found? I clearly define it in Block 3, no?

Again, this has to do with the way scope works in Java. The moment we exit a block, we lose the ability to reach all of the identifiers defined within that block. This means z effectively vanishes from the perspective of the compiler the moment we exit Block 3 (Line 12).

Scope rules also allows us to reuse old identifiers so long as we do not use the same identifier in the same scope. For example, take a look at the following code which defines x twice in main:

1: public class Dec{
2:     public static void main(String[] args){
3:         int x = 1; //Declaring x
4:         int x = 2; //Declaring x, again
5:     }
6: }

If I try to compile that code:

josephraskind@stargazer:/tmp/scope$ javac Dec.java 
Dec.java:4: error: variable x is already defined in method main(String[])
        int x = 2; //Declaring x, again
            ^
1 error

I get an error that tells me I "already defined" x. This happens because all identifiers within a given scope must be unique. I cannot have two different memory locations tied to the same name, there must be a one-to-one mapping within a scope between name and memory location at all times. If I wanted to fix the above error, I would need to define each x in their own, mutually exclusive scopes (I will leave that as an exercise for the reader).

Scope will become relevant again when we discuss functions!

What a Variable Really Is in Java

In Java, variables are not purely symbolic names. They are intimately tied up with the memory semantics of the JVM runtime system. They are truly just standins for locations in memory3.

To illustrate this I will write a simple Java program which declares two int variables and adds them together and stores the result in a third variable:

1: public class Adder{
2:     public static void main(String[] args){
3:         int a = 100;
4:         int b = 200;
5:         int c = a + b;
6: 
7:     }
8: }

Then I will compile the program down to its JVM bytecode representation with javac Adder.c; javap -c Adder.class. We can see the resultant JVM bytecode file here:

 1: Compiled from "Adder.java"
 2: public class Adder {
 3:   public Adder();
 4:     Code:
 5:        0: aload_0
 6:        1: invokespecial #1                  // Method java/lang/Object."<init>":()V
 7:        4: return
 8: 
 9:   public static void main(java.lang.String[]);
10:     Code:
11:        0: bipush        100
12:        2: istore_1
13:        3: sipush        200
14:        6: istore_2
15:        7: iload_1
16:        8: iload_2
17:        9: iadd
18:       10: istore_3
19:       11: return
20: }

The main method's Code label shows where our program's code begins. We can see our constants clearly on Lines 11 and 13 which must mean that istore_1 and istore_2 are directly related to a and b, respectively. How can that be? The constants are stored inside of the JVM's local variable array. It is nothing more than a location in memory which is managed by the JVM. By the time we reach JVM runtime land, we no longer have symbolic names like a and b, but rather purely locations in memory managed by the JVM runtime which is outlined by the compiler.

Exercises

  1. Look at Listing 4 again, and edit the code such that x is defined twice in main, but the compiler does not throw any errors.
  2. Compile Listing 6 with javac Adder.java and inspect the bytecode with javap -c Adder.class. Identify which lines in the bytecode correspond to each of the three variable declarations. What local variable slots are used for a, b, and c? Why do you think slot 0 is skipped?
  3. Modify Listing 6 to add a fourth variable int d = c * 2 and recompile. Run javap -c again. What new bytecode instructions appear? Which slot is d assigned to?
  4. Write a Java program that declares a static field static int g = 10 outside main and a local variable int g = 20 inside main. Does it compile? Which value gets printed and why? Now try to print the static g from inside the block that defines the local g using Classname.g—where Classname is replaced with the name of your class—is it possible?
  5. The lecture states that once a block is exited its variables "vanish from the perspective of the compiler." Write a Java program that demonstrates this by attempting to access a variable from an inner block after that block has closed. Record the exact compiler error you receive and explain in your own words what it means in terms of scope.
  6. Earlier in the lecture, I wrote the code snippet x = x + 1 and referred to it as "incrementing" x. Outside of computer science, x = x + 1 likely looks like a nonsense statement. From what you now know about variables, how is that possible in a programming language? Write a Java program that defines an integer x, assigns it the value 100, and increments it by 200. Then inspect the bytecode with javap -c to see how the JVM represents this operation.

Footnotes:

1

All subsequent references to "variables" will be references to "variables" in the computer science sense.

2

C Programming Language - Second Edition, K&R.

3

This will return when we talk about references.

Contact: [email protected] | rss feed | Compiled with org-mode | Licensed under CC BY-NC-SA 4.0