Variables and assignment

Beginner30 min

Explain names, binding and mutation, and trace how a program's variables change as it runs.

What you will learn
  • Explain a variable as a name bound to a value
  • Trace assignments and reassignments in a variable table
  • Distinguish rebinding a name from mutating a value
  • Choose clear names and use constants for fixed values
On this page

A program that could only handle values written directly into its code would be a calculator with a fixed answer. Variables let a program hold on to results, give them meaningful names, and use them later.

Names and values

A variable is a name that refers to a value. Assignment is the act of attaching a name to a value, and the symbol for it is usually =.

Python

score = 10

JavaScript

let score = 10;

Java

int score = 10;

C

int score = 10;

Despite the symbol, = does not mean “equals” as in mathematics. It means “evaluate the right side, then store the result under the name on the left”. That is why this is legal and meaningful:

score = score + 1

Read it as: take the current value of score, add one, store the answer back in score. As algebra it would be nonsense; as an instruction it is one of the most common lines in programming.

Two parts of the picture to keep apart:

  • The name (score) is a label.
  • The value (10) is the data, with a type.

In statically typed languages such as Java and C, the name also carries a declared type (int). In Python and JavaScript, only the value has a type, and the name can later point at a different kind of value.

Reassignment and tracing

Assigning to a name that already exists rebinds it. The old value is forgotten (if nothing else refers to it). A variable table records this:

price = 20
quantity = 3
total = price * quantity
quantity = quantity + 1
After line price quantity total
1 20 - -
2 20 3 -
3 20 3 60
4 20 4 60

Note that total stays 60 on line 4. It was computed once, from the values at that moment. It does not track quantity. Beginners often expect a variable to behave like a spreadsheet formula; it does not.

The same four lines as a program, which prints the variables after the last line:

Python

trace_vars.py
price = 20
quantity = 3
total = price * quantity
quantity = quantity + 1
print(price, quantity, total)

JavaScript

trace_vars.js
let price = 20;
let quantity = 3;
let total = price * quantity;
quantity = quantity + 1;
console.log(price, quantity, total);

Java

TraceVars.java
public class TraceVars {
public static void main(String[] args) {
int price = 20;
int quantity = 3;
int total = price * quantity;
quantity = quantity + 1;
System.out.println(price + " " + quantity + " " + total);
}
}

C

trace_vars.c
#include <stdio.h>
int main(void) {
int price = 20;
int quantity = 3;
int total = price * quantity;
quantity = quantity + 1;
printf("%d %d %d\n", price, quantity, total);
return 0;
}

All four print the last row of the table:

20 4 60

Swapping two variables

The classic puzzle: exchange the values of a and b. You cannot just write a = b then b = a, because the first line destroys the original a. The method that works in every language is a temporary variable: park one value, overwrite, then restore.

a b temp
1 2 - start
1 2 1 temp = a
2 2 1 a = b
2 1 1 b = temp

Python

swap_temp.py
a = 1
b = 2
temp = a
a = b
b = temp
print(a, b)

JavaScript

swap_temp.js
let a = 1;
let b = 2;
const temp = a;
a = b;
b = temp;
console.log(a, b);

Java

SwapTemp.java
public class SwapTemp {
public static void main(String[] args) {
int a = 1;
int b = 2;
int temp = a;
a = b;
b = temp;
System.out.println(a + " " + b);
}
}

C

swap_temp.c
#include <stdio.h>
int main(void) {
int a = 1;
int b = 2;
int temp = a;
a = b;
b = temp;
printf("%d %d\n", a, b);
return 0;
}

All four print:

2 1

Some languages can skip the temporary with simultaneous assignment, which evaluates the whole right side before storing anything. Java and C have no such syntax, so they always use the temporary.

Python

swap_tuple.py
a, b = 1, 2
a, b = b, a
print(a, b)

JavaScript

swap_destructure.js
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b);

Java

Java has no simultaneous assignment. Use the temporary variable shown above.

C

C has no simultaneous assignment. Use the temporary variable shown above.

Both programs print 2 1.

A third trick swaps numbers with arithmetic and no spare variable: a = a + b, then b = a - b, then a = a - b. It only works for numbers, and it can overflow in languages with fixed-size integers. Treat it as a curiosity.

Rebinding versus mutating

After one variable is assigned to another, something surprising can happen. Take a list, give it a second name, and change the list through the second name:

x -----> [1, 2]
y = x (now both names point at the same list)
x ---+
+--> [1, 2, 3] after adding 3 through y
y ---+

Python

alias_list.py
x = [1, 2]
y = x
y.append(3)
print(x, y, x is y)

JavaScript

alias_list.js
const x = [1, 2];
const y = x;
y.push(3);
console.log(x, y, x === y);

Java

AliasList.java
import java.util.ArrayList;
import java.util.List;
public class AliasList {
public static void main(String[] args) {
List<Integer> x = new ArrayList<>(List.of(1, 2));
List<Integer> y = x;
y.add(3);
System.out.println(x + " " + y + " " + (x == y));
}
}

C

C arrays cannot grow, so this version changes an existing slot instead of appending. The pointer y holds the address of x’s first element.

alias_list.c
#include <stdio.h>
int main(void) {
int x[3] = {1, 2, 0};
int *y = x;
y[2] = 3;
printf("%d %d %d, same place: %d\n", x[0], x[1], x[2], x == y);
return 0;
}

Python prints [1, 2, 3] [1, 2, 3] True, JavaScript prints [ 1, 2, 3 ] [ 1, 2, 3 ] true, Java prints [1, 2, 3] [1, 2, 3] true, and C prints 1 2 3, same place: 1. In every language the change made through y shows up in x, because there is only one list and two names for it. The identity check at the end confirms it.

  • Rebinding: y = something_else points the name y at a different value. Other names are unaffected.
  • Mutation: changing the contents of the value itself. Every name pointing at it sees the change.

Simple values like numbers and strings are typically immutable (they cannot be changed in place), so the issue arises with collections and objects. The lesson on memory and references covers this properly; for now, remember that = between variables does not always copy.

Constants and naming

A constant is a name that should not change after it is set.

Python

MAX_ATTEMPTS = 3 # capital letters by convention; Python will not stop you reassigning

JavaScript

const MAX_ATTEMPTS = 3; // reassigning is an error

Java

final int MAX_ATTEMPTS = 3; // reassigning is a compile error

C

const int MAX_ATTEMPTS = 3; /* reassigning is a compile error */

Some languages enforce this and some rely on convention. Either way, giving a fixed number a name such as MAX_ATTEMPTS beats scattering a bare 3 through your code: the name says what it means, and you change it in one place.

For naming in general:

  • Pick names that say what the value is: elapsed_seconds rather than x or data2.
  • Follow your language’s convention. Python and C favour snake_case; JavaScript and Java favour camelCase. Constants are usually UPPER_SNAKE_CASE.
  • Names are case-sensitive in nearly every language: total and Total are different.
  • Names usually cannot start with a digit or contain spaces, and cannot reuse reserved words such as if or while.

Common pitfalls

  • Using a variable before it has a value. Most languages report this as an error; C may silently give you garbage.
  • Expecting = to link values. Changing quantity does not update an earlier total.
  • Typos in names. In a dynamic language, misspelling a name on assignment can silently create a new variable instead of updating the old one.
  • Reusing one name for unrelated purposes. A variable that is a count on line 5 and a filename on line 20 invites bugs.
  • Assuming assignment copies. For collections it often shares.
ExerciseTrace a variable table

Trace this program and give the final values of a, b and c. There is no input.

a = 5
b = a * 2
a = a + b
c = a - b
b = c

Expected: three whole numbers, one for each variable.

Show solution
After line a b c
1 5 - -
2 5 10 -
3 15 10 -
4 15 10 5
5 15 5 5

Final values: a is 15, b is 5, c is 5. Line 5 copies the value of c into b; it does not tie them together afterwards.

ExerciseSpot the broken swap

Why does this fail to swap a and b? Trace it with a = 1 and b = 2. Expected: the values of a and b after the two lines.

a = b
b = a
Show solution

After a = b, both a and b hold 2, and the original 1 is gone. Then b = a copies 2 into b, which is already 2. The result is a = 2, b = 2. A swap must save one value first (the temporary variable) or use simultaneous assignment.

ExerciseTwo names, one list

After this runs, what do x and y contain? Explain why. Expected: the contents of each name.

x = [1, 2]
y = x
y.append(3)
x = [9]
Show solution

y is [1, 2, 3] and x is [9]. The append mutates the one shared list, which is why both names would have shown [1, 2, 3] at that point. The last line rebinds x to a brand-new list, which leaves y still pointing at the old one.

ExerciseRotate three values

Start with a = 1, b = 2, c = 3. Using only assignments and one temporary variable, rotate the values so a holds 2, b holds 3 and c holds 1. Print the three values on one line. Expected output: 2 3 1.

Show solution

Park the first value, then shift each one into the place before it, then put the parked value last.

Python

rotate_three.py
a = 1
b = 2
c = 3
temp = a
a = b
b = c
c = temp
print(a, b, c)

JavaScript

rotate_three.js
let a = 1;
let b = 2;
let c = 3;
const temp = a;
a = b;
b = c;
c = temp;
console.log(a, b, c);

Java

RotateThree.java
public class RotateThree {
public static void main(String[] args) {
int a = 1;
int b = 2;
int c = 3;
int temp = a;
a = b;
b = c;
c = temp;
System.out.println(a + " " + b + " " + c);
}
}

C

rotate_three.c
#include <stdio.h>
int main(void) {
int a = 1;
int b = 2;
int c = 3;
int temp = a;
a = b;
b = c;
c = temp;
printf("%d %d %d\n", a, b, c);
return 0;
}

All four print:

2 3 1

Summary

  • A variable is a name bound to a value; = stores the result of the right side under the left name.
  • Reassignment rebinds a name, while mutation changes a shared value; the difference explains many surprising bugs.
  • Prefer clear names, follow your language’s conventions, and name fixed values as constants.

Next: Expressions and operators.