Variable

On this page 7

A variable is a named binding between an identifier and a value that a program can read and, in most cases, change while it runs. In programming, variables are the most basic way to store intermediate results, carry state and pass data between the steps of an algorithm, which is why they belong to the core of programming fundamentals.

Behind the simple idea of a name for a value sit several precise properties: a type, a scope, a lifetime and a storage location. How a language defines these properties shapes its safety, its performance and the kinds of bugs developers meet most often.

How a variable binds a name to a value

A variable works by associating an identifier in the source code with a location or object at run time. When the program executes count = 3, the language either writes the value 3 into a memory slot reserved for count, as in C, or makes the name count refer to an integer object, as in Python. Both models are called variables, but they behave differently when values are copied or shared.

Three operations define the life of a variable. Declaration introduces the name, initialization gives it a first value and assignment replaces that value later. Some languages merge the first two; others, such as Rust, forbid reading a variable before it is initialized and catch the mistake at compile time.

The table below lists the properties that together describe any variable.

PropertyQuestion it answersExample
NameHow code refers to the valuetotal_price
TypeWhich values and operations are allowed32-bit integer, string, list
ValueWhat the variable currently holds42 or a reference to an object
ScopeWhere in the source the name is visibleInside one function or block
LifetimeHow long the storage exists at run timeUntil the function returns
MutabilityWhether the binding or value may changeconst, final, let mut
Properties that define a variable

Scope and lifetime of variables

Scope is a compile-time idea: it defines the region of source code in which a name can be used. Lifetime is a run-time idea: it defines how long the underlying storage exists. The two often coincide, but not always, because a closure can keep a local variable alive after its enclosing function has returned.

Most modern languages use lexical scoping, meaning that visibility follows the nesting of the source text. A name declared inside a block shadows an outer name with the same spelling, which is legal but frequently confusing.

Scope levelVisible inTypical lifetimeMain risk
Block scopeOne loop body or conditional branchUntil the block endsShadowing an outer name
Function scopeThe whole function bodyOne function callLong functions with many names
Module scopeOne source file or moduleWhole program runHidden coupling between functions
Global scopeEvery part of the programWhole program runUnpredictable changes from anywhere
Common scope levels

The practical rule is to declare each variable in the narrowest scope that works. Narrow scope shortens the distance between where a value is set and where it is used, which makes code easier to read and reduces accidental interference.

Typing and storage models

Languages attach types to variables in two main ways. In static typing, the variable itself has a declared or inferred type that the compiler checks before the program runs, as in Java, C++, Rust or TypeScript. In dynamic typing, the type belongs to the value, and a variable may hold an integer at one moment and a string at the next, as in Python or JavaScript.

Storage is the second axis. Value semantics copy the data on assignment, so changing the copy leaves the original untouched. Reference semantics copy only a pointer to shared data, so two variables can observe the same change. Confusing the two is one of the most common sources of bugs for developers switching languages.

LanguageTypingDefault assignment behaviorImmutable binding
CStaticCopies the valueconst
JavaStaticCopies primitives, shares object referencesfinal
PythonDynamicBinds the name to the same objectNo keyword, convention only
JavaScriptDynamicCopies primitives, shares object referencesconst
RustStaticMoves ownership unless the type is CopyImmutable by default, mut to change
How several languages treat variables

A variable sits next to several neighboring terms that are easy to blur. A constant is a binding that cannot be reassigned, although in many languages the object it refers to may still change internally. A parameter is a variable declared in a function signature and filled with an argument at each call, and a return value is the result a function hands back, which is usually stored in a variable by the caller.

  • Variable versus constant: a const list in JavaScript cannot be reassigned, yet items can still be pushed into it.
  • Variable versus field: a field or attribute belongs to an object and lives as long as that object, not as long as a function call.
  • Variable versus pointer: a pointer is a variable whose value is a memory address, which adds one level of indirection.

Naming conventions and common mistakes

A good variable name states what the value means, not how it is stored. Names such as retry_count or invoiceTotal explain intent, while x2 or tmpData force the reader to reconstruct it. Each language community fixes a casing style, for example snake_case in Python and camelCase in JavaScript and Java.

SymptomCauseFix
Unpredictable or garbage valueReading before initializationInitialize at declaration; enable compiler warnings
Change appears in an unrelated placeShared reference mistaken for a copyCopy explicitly or use immutable data
Wrong value inside a nested blockShadowing an outer nameRename the inner variable; enable lint rules
Race conditions between threadsShared mutable global statePass values explicitly or synchronize access
Silent wrong arithmeticInteger overflow in a fixed-width typeChoose a wider type or checked arithmetic
Frequent variable mistakes

The strongest general recommendation is to prefer immutable bindings by default and introduce mutation only where a value genuinely changes. Code written this way is easier to test and reason about, and it is safer under concurrency.

Put simply

A variable is like a labeled box on a shelf. The label is the name, and whatever sits inside is the current value. A program can look into the box, use what it finds and replace the contents with something new.

Some boxes are only allowed to hold certain things, such as numbers, and some are sealed after the first use. The key idea is simple: a variable lets a program remember a value under a name so it can use that value later.

In practice

A developer writes a checkout function for an online shop. A variable subtotal, declared with a decimal type to avoid binary rounding errors, starts at 0 and grows as the function loops over the cart: three items priced at 19.99, 5.50 and 12.00 bring it to 37.49. A second variable discount_rate holds 0.10 for a returning customer, and a third, total, stores the result of subtotal * (1 - discount_rate), which is 33.741, rounded to 33.74 for display.

During code review, a colleague notices that discount_rate was declared at module scope and modified by another function. The developer moves it into the function as a parameter with a default value and marks the price list as immutable. The result is a function whose output depends only on its inputs, which makes the unit tests deterministic and removes a hidden dependency.