Why does this print the new city without a capture list, and the old one with [city]?
Predict first
What do the two prints show?
struct City { var name: String }
var city = City(name: "Pune")
let byReference = { city.name }
let byValue = { [city] in city.name }
city.name = "Goa"
print(byReference(), byValue())
- Goa Goa
- Goa Pune
- Pune Pune
- Pune Goa
Mental model. Without the list you left a note saying “look at the whiteboard”. With it you photographed the whiteboard.
city is a struct stored in a variable. A closure that mentions city without a capture list captures the variable slot — so it reads whatever value is there when the closure runs. Mutating city afterwards changes what the closure sees.
[city] evaluates city immediately and copies the value into the closure's context. Later mutation of the variable cannot reach that copy.
Without a capture list the closure captures the variable, so it sees the change. [city] copied the value when the closure was created.
Code
struct City { var name: String }
var city = City(name: "Pune")
let byReference = { city.name } // captures the variable slot
let byValue = { [city] in city.name } // captures a copy
city.name = "Goa"
print(byReference()) // ?
print(byValue()) // ?
Goa / Pune
Common traps
- “Structs are always copied into closures.” Only with a capture list. Without one, the closure captures the variable, not the value.
- Assuming this only matters for structs. For a class, the “variable” and the object are different things — capture lists change ownership, not the object identity.
They might follow up with
- What if
citywere a class? Both closures would see the same object and print the new name — unless the variable was reassigned to a different instance. - What if the closure is
@escaping? Same rule; the capture happens at creation either way. Escaping only affects where the context lives.
Related questions
- 1.5.4 What does a capture list like [weak self], [unowned self], [self], or [foo] actually do?
- 1.5.3 Why are closures called reference types? What is a closure context?
- 1.5.6 unowned var view = UIView() then print(view) — what happens?
← What does a capture list like [weak self], [unowned self], [self], or… unowned var view = UIView() then print(view) — what happens? →