Programming · intermediate
Value vs reference semantics
With value semantics, copying a value produces independently changeable state at the abstraction level of the type. With reference semantics, copying a reference can create another alias to the same object, so mutations through one alias are observable through the other.
Why it matters
Function calls, assignments, collection updates, concurrency, and API design behave differently when data is copied versus aliased. Correct reasoning must follow the specific language and type rather than slogans such as pass by reference.
Mental model
How to reason about value vs reference semantics
Draw names or fields as boxes. A value copy duplicates the represented state into another box; a reference copy duplicates an arrow, leaving two arrows aimed at one mutable object. Languages frequently mix both models and optimize copies without changing semantics.
Analogy
Value copying is giving someone a photocopy they can mark independently; reference copying is giving them another key to the same whiteboard, where either person's edits are shared.
Examples
See the boundary, not just the happy path
Worked example · Reference alias observes mutation
items = ['a']
alias = items
alias.append('b')
# items is now ['a', 'b']In Python, both names are bound to the same list object. append mutates that shared object rather than rebinding alias.
Worked example · Copy breaks list aliasing
items = ['a']
copy = items.copy()
copy.append('b')The shallow copy creates a distinct outer list, so appending does not change items. Nested mutable elements would still be shared unless copied more deeply.
Useful contrast · Rebinding is not object mutation
alias = ['new']This changes which object alias refers to; it does not alter the old list still referenced by items. Assignment and mutation have distinct effects.
Common mistakes
Misconceptions to remove early
Labelling an entire language pass-by-reference
Parameter passing rules are language-specific. For example, Python passes object references by value: a callee can mutate a passed mutable object but rebinding its parameter does not rebind the caller's name.
Assuming a shallow copy removes all sharing
A shallow copy duplicates the outer container but retains references to its elements. Nested mutable objects can therefore remain aliased.
Quick check
Can you predict the result?
1. Two variables refer to the same mutable list. What makes a change visible through both?
- • Mutating the shared list object through either reference.
- • Rebinding one variable to a new list.
- • Printing one variable without modifying it.
2. Why can a shallow copy still share mutable state?
Keep building