Variables
Why Do We Need Variables?
Think about a basic physical calculator. You punch in a number, multiply it, and get a result. If you need that result again later, you either write it on paper or use the calculator's memory button.
Programs process data millions of times a second. If we type 0.075 every time we want a 7.5% tax rate, the code becomes brittle: when the rate changes next year, we have to hunt down every copy.
We need a way to store information, give it a name, and reuse it. We need a variable.
What Is a Variable?
Definition
A variable is a named entity in a program that refers to a value, and that can be given a new value as the program runs.
Three things are worth keeping in mind whenever you meet one:
- The name you use to refer to it, such as
taxRate. - The value it currently refers to, such as
0.075. - The type of that value, which decides what may be done with it.
How those three are represented, and how tightly they are tied together, differs from language to language.
If a data type is the kind of information, a variable is how your program refers to a particular piece of it.
Note
A box in memory is a good picture and a poor rule. A compiler may keep a variable in a CPU register, reuse one slot for several variables, or work the value out while compiling and never store it at all. Memory picks this up properly.
Declaring a Variable
Before a program can refer to a variable, the variable must be introduced according to the language's rules. This is called declaration. In a statically typed language you also state what kind of value it will hold:
int score; // "I need a box for an integer, label it 'score'"String username; // "I need a box for text, label it 'username'"The name now exists and the program knows its type. Whether it also has a usable value depends on where it was declared: the two above are Java locals, which have none yet, while a field on an object is given 0, false or null automatically.
Initializing a Variable
Initialization gives the variable its first value.
score = 0;Usually the two are combined into one line, which is the common case:
int score = 0;Trying to read a variable before it has a valid value is handled differently across languages:
- Java refuses to compile: a local must be definitely assigned before it is read.
- Python raises a
NameErrorthe moment you try. - C and C++ allow some variables to exist without an explicit initializer, but reading an uninitialized value can lead to invalid or undefined behaviour depending on the language, type, and context.
As a good programming habit, initialize a variable before you rely on its value. The exact rules for uninitialized variables depend on the language and context.
Assigning and Updating Values
Changing a variable's value later is reassignment, and this is where = catches beginners out. It does not mean "is equal to"; it means assign the value on the right to the variable on the left.
score = 50 # Put 50 into the score variablescore = 100 # Throw away the 50, put 100 in the score variableThe rule is that the right-hand side is evaluated first, and the resulting value is assigned to the variable on the left. That is why you will see this line everywhere:
score = score + 10In maths, x = x + 10 is impossible. In programming it makes sense: the right side is worked out first (score + 10), and that total is then assigned back to score.
Variables and Memory
Variables are a programming abstraction for referring to values. Where a value is actually kept - memory, a CPU register, somewhere else again - is handled by the language implementation.
We will study how variables relate to memory in the Memory chapter.
Variables and Types
Two ideas get confused here, so it is worth separating them.
In a statically typed language, the type of a variable or expression is determined and checked by the language's compile-time type system:
int age = 25;age = "Hello"; // error: String is not assignable to intIn a dynamically typed language, type checking happens at runtime, and a name can be associated with values of different types over time:
age = 25 # age refers to an integer objectage = "Hello" # now it refers to a string objectNothing is converted and no box is swapped: age is a name, and rebinding it points it elsewhere.
Note
Type inference is a third, separate idea. Java's var age = 25; and C++'s auto age = 25; let the compiler work the type out from the initial value. age is still an int, still checked at compile time, and still cannot hold a string later - inferred rather than written down, and no less static for it.
Naming Variables
The name is called an identifier, and the rules are strict: letters, digits and underscores only, no spaces, never starting with a digit (user1 is valid, 1user is not), and case-sensitive, so Score and score are different variables.
Because spaces are out, conventions fill the gap:
- camelCase: First word lowercase, every later word capitalised (
highestPlayerScore). Conventional in Java and JavaScript. - snake_case: All lowercase, words separated by underscores (
highest_player_score). Conventional in Python. - PascalCase: Every word capitalised (
HighestPlayerScore). Usually reserved for classes and types rather than variables.
These are conventions, not language rules: the compiler accepts any legal identifier. C++ has no single standard, and both forms are common depending on the project.
Booleans read best as a question. Prefixing with is, has or can makes the code read like a sentence: isLoggedIn, hasPermission, canEdit. Compare if (isLoggedIn) with if (login).
Meaningful names are critical. Code is read far more often than it is written, and x tells the reader nothing where daysUntilExpiration explains exactly what the data is doing.
Constants
Sometimes a program should prevent a variable or binding from being reassigned. Languages provide constants or constant bindings for this purpose: pi, a tax rate, a configuration setting.
- Java: Uses the
finalkeyword (final double PI = 3.14159;) - C++ / JavaScript: Uses the
constkeyword (const double PI = 3.14159;) - Python: Has no language-enforced constant for an ordinary variable. By convention, a name in
ALL_CAPSsignals that it should not be reassigned (PI = 3.14159).
Reassigning a constant is caught at different moments. Java and C++ reject it while compiling, so the program never builds. JavaScript throws a TypeError while the program is running.
Note
A constant stops the name being reassigned. It does not always freeze what the name refers to.
const user = {};user.name = "Ashu"; // allowed: the object is changed, not the bindinguser = {}; // TypeError: the binding cannot be reassignedThese keywords are similar in purpose, but their exact semantics differ. In JavaScript, const prevents reassignment of the binding. In Java, final prevents reassignment of the variable. C++'s const is part of its type system and can also make an object non-modifiable through that particular access.
Scope of a Variable
Scope is the region of a program in which a name can be used. The rules belong to the language, but three levels turn up almost everywhere:
- Local: the variable belongs to the function that declared it.
- Block: it belongs to a smaller region inside a function, such as the body of an
ifor afor. - Module or global: it is declared outside any function, and a wider part of the program may reach it.
How those regions are marked differs. Java and C++ use braces to define many block scopes, so a variable declared inside an if cannot be referred to after that block. Python has no block scope here: a name first assigned inside an if is still visible afterwards, because Python's unit is the function. In JavaScript, let and const are block-scoped while the older var is function-scoped, which is why modern code prefers the first two.
Declare int playerHealth = 100; inside a "Start Game" function, then try to use it in an "End Game" function, and the program will not compile: the name is not in scope there.
Scope vs Lifetime
Scope describes where a variable can be accessed. Lifetime describes how long that variable exists during execution.
They are related but different, and one more point is worth knowing now: the lifetime of a variable is not necessarily the lifetime of an object it refers to. Stack and Heap takes that apart.
Variables Across Languages
| Feature | Java / C++ | Python | JavaScript |
|---|---|---|---|
| Declaration | int age = 25; | age = 25 | let age = 25; |
| Typing | Static | Dynamic | Dynamic |
| Reassignment | Checked against the language's type rules | Can be any type | Can be any type |
| Constants | final / const | ALL_CAPS convention | const |
Java and C++ need a variable's type to be known while compiling, but that does not mean you always write it out: var age = 25; in Java and auto age = 25; in C++ let the compiler work it out from the value. Both are still statically typed.
Variables in DSA
Almost every algorithm you will write is a small number of variables being updated in a loop:
- Counters and positions such as
i,leftandrighttrack where you are in a structure. (Positions, not pointers in the C++ sense - the word gets used loosely for both.) - Accumulators such as
sum,countandmaxare usually initialized before the loop, so their value carries from one iteration to the next. Initializing them inside resets them every pass, one of the most common beginner bugs. - A temporary is what makes a swap possible:
temp = a; a = b; b = temp;- something sorting algorithms do thousands of times. - In recursion, each function call gets its own set of local variables. That is why a recursive function can have different values for the same local variable in different calls, and why deep recursion costs memory.
Common Mistakes
Watch out
- Using a variable before initialization: Asking the computer to print
scorebefore you have assigned a number to it. - Confusing
=with==:=assigns a value.==checks if two values are equal. Writingif (score = 100)instead ofif (score == 100)will break your code. - Using an invalid identifier: Trying to start a variable name with a number (
1stPlace). - Re-declaring instead of updating: Declaring a fresh variable inside a loop when you meant to update the one outside it, then wondering why the total never grows.
- Expecting a constant to freeze an object:
finalandconststop the name being reassigned, not the object being modified.
Quick Check
- What is the difference between declaring a variable and initializing it?
- What does the
=operator actually do? - Can a constant be reassigned after it has been initialized?
- If a local variable is declared inside one function, can another function access that variable directly?
- Why is a variable named
uworse than a variable namedactiveUserCount?
Show answerHide answer
- Declaration reserves the storage and fixes the name, and in a statically typed language the type as well. Initialization puts the first value into it.
int score;declares,score = 0;initializes, andint score = 0;does both. - It assigns. The expression on the right is evaluated first, and the result is stored in the variable on the left. It is not a claim that the two sides are equal, which is why
score = score + 10makes sense in code and not in algebra. - No. Java and C++ reject the reassignment at compile time, and JavaScript throws a
TypeErrorat run time. Python has no enforced constants, only theALL_CAPSconvention. - No. A local name exists only inside its own scope, so another function cannot refer to it. You share the value instead - by passing it as an argument, returning it, or using whatever wider scope the language provides.
- Because the name is the only explanation most readers get.
uforces them to read the surrounding code to work out what it holds;activeUserCountsays it outright, and code is read far more often than it is written.
Quick Recap
- A variable is a name your program uses to refer to a value, and it can usually be given a new one.
- Declaration introduces the variable; initialization gives it its first value.
- Assignment (
=) evaluates the right-hand side first, then assigns the result to the name on the left. - Static typing fixes the type at compile time; dynamic typing attaches it to the value. Type inference is separate again.
- Scope is where a name can be used; lifetime is how long it exists - and neither is the same as the lifetime of a value it refers to.
- Constants cannot be reassigned, which is not the same as the value being unchangeable.
- Good naming carries more meaning than any comment, and booleans read best as a question:
isLoggedIn,hasPermission.
Where This Leads
You can now identify what kind of value you are working with (Data Types) and give that value a name your program can use (Variables). Next comes doing something with it, which takes maths, logic and comparisons: Operators.
Data Types → Variables → Operators → Conditions → Loops → Functions → Memory
Key takeaway
A variable gives your program a name for a value, making that value easy to access and, when allowed by the language, update.