Programming · foundation

Variables and scope

A variable is a language-defined binding between a name and a value, storage location, or object reference. Scope is the region of program text or execution context in which a particular binding can be resolved by that name.

Why it matters

Scope determines which value code reads, where names can collide, what a closure captures, and whether changing a name affects shared state or merely creates another binding.

Mental model

How to reason about variables and scope

Name lookup searches the environment prescribed by the language, often moving from an inner lexical scope toward enclosing scopes. A nearer binding can shadow a farther one without modifying it.

Analogy

Scope resembles labelled drawers in nested rooms: code checks the nearest room's drawer first, then enclosing rooms according to the building's lookup rules.

Examples

See the boundary, not just the happy path

Worked example · Local binding shadows an outer name

x = 'outer'
def show():
    x = 'inner'
    return x

In Python, assigning x in show makes it local to that function unless declared otherwise. Calling show returns inner while the module-level x remains outer.

Worked example · Closure resolves an enclosing binding

def multiplier(factor):
    return lambda value: factor * value

The returned function refers to factor from its enclosing lexical scope. The binding remains available through the closure after multiplier has returned.

Useful contrast · Shell environment is a different mechanism

export PORT=8080

An environment variable is process configuration inherited by child processes. It is not automatically a lexical variable in a programming language, even when both use a name such as PORT.

Common mistakes

Misconceptions to remove early

Equating scope with lifetime

Scope governs where a name can be resolved; lifetime governs how long a value or storage remains alive. A closure can keep captured state alive after the original call's local scope has finished.

Mistaking shadowing for mutation

Creating a nearer binding with the same name can leave the outer binding untouched. Mutation changes the state of an existing mutable object or location.

Quick check

Can you predict the result?

1. What does lexical shadowing do?
  • It makes a nearer binding with the same name take precedence in its scope.
  • It deletes every outer binding with that name.
  • It converts the variable into an environment variable.
Answer: It makes a nearer binding with the same name take precedence in its scope.
2. How can a captured value outlive the function call that created its local binding?
Answer: A closure retains access to the enclosing binding according to the language's runtime model.

Keep building

Authoritative references

Make the idea retrievable.

Study this concept with spaced repetition, next to the commands where you use it.

Get Terminaster