2

In Capturing Values section of swift documentation:

... It does this by capturing a reference to runningTotal and amount from the surrounding function and using them within its own function body. ...

and

If you create a second incrementer, it will have its own stored reference to a new, separate runningTotal variable.

So I try the following testing and get a conclusion that since each incrementer made by the makeIncrementer(forIncrementer:) has its own runningTotal and the value of runningTotal is remembered by each incrementer, what values-capturing does is equivalent to creating some static variable(s) for a closure. But I'm not sure whether my statement is correct.

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }

    return incrementer
}

let by10Incrementer = makeIncrementer(forIncrement: 10)
let by20Incrementer = makeIncrementer(forIncrement: 20)

for i in 0..<5 {
    print(by10Incrementer())
}

print("---")

for j in 0..<5 {
    print(by20Incrementer())
}

output:

10
20
30
40
50
---
20
40
60
80
100

I originally thought that the output of by20Incrementer() would start from 50, but it starts from 0. So the runningTotal of each incrementer refers to different one.

D4ttatraya
  • 3,344
  • 1
  • 28
  • 50
Kindred
  • 1,229
  • 14
  • 41
  • 1
    Captured values are put into reference-counted boxes on the heap, which are then stored on the function's context object (although as an optimisation, can be stack-promoted in some cases) – compare https://stackoverflow.com/a/40979548/2976878 & (if you're interested in the nitty gritty details) https://stackoverflow.com/q/43171341/2976878. – Hamish Jun 05 '17 at 15:20
  • FWIW, it helps me to think of functions as a Type rather than a traditional function. – GetSwifty Jun 05 '17 at 15:43

1 Answers1

3

Captures do not become static in a closure, in the sense that each instance of the closure gets its own copy of the variable.

I originally thought that the output of by20Incrementer() would start from 50, but it starts from 0

It starts from the value of runningTotal at the time the closure is created, which is always zero. No matter how many times you increment runningTotal in by10Incrementer, it wouldn't change the value of runningTotal captured in by20Incrementer, because it is a different instance with its own capture of runningTotal.

Effectively, runningTotal becomes a var on the object that represents the closure. Swift syntax makes this capture implicit, but internally the variable is there.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523