Reputation: 103
I'm reading a book on swift and came across this example of closure value capturing.
func makeStateMachine(maxState: Int) -> StateMachineType {
var currentState: Int = 0
return {
currentState++
if currentState > maxState {
currentState = 0
}
return currentState
}
}
let bistate = makeStateMachine(1)
println(bistate());
println(bistate());
println(bistate());
println(bistate());
The output should be '1 0 1 0 '
I understand how the return block captures the local value 'currentState' value after the function executes, but why isn't this value set back to 0 on the next function call? Is it because of the instance of the bistate constant? Or is it because currentState is initialized with a value 0 on the bistate initialization and the compiler infers that
var currentState: Int = 0
is ignored? I'm confused on how the above line is treated after the first call.
Upvotes: 4
Views: 1136
Reputation: 70155
Nobody seems to have explained it...
The function makeStateMachine
returns a closure having captured two variables: maxState
and currentState
. When invoked with a maxState
of 1
, the returned closure will increment currentState
, compare it to 1
and then reset currentState
to 0
if 1
is exceeded. Given multiple calls to the returned closure, the sequence of return values is 1, 0, 1, 0, ...
. More generally, for any maxState
the sequence is 1, ..., maxState, 0, ..., maxState, ...
Upvotes: 1
Reputation: 70142
author of that book chapter here :-)
Yes, I can confirm that your comment is correct, the function returns a closure. I've added a few comments that hopefully clarify things:
func makeStateMachine(maxState: Int) -> StateMachineType {
// this variable is initialised when makeStateMachien is invoked
var currentState: Int = 0
// the function returns this closure
return {
// by using 'currentState' this variable is captured
currentState++
if currentState > maxState {
currentState = 0
}
return currentState
}
}
When this function is invoked:
let bistate = makeStateMachine(1)
The constant bistate
now holds a reference to the closure that was returned by makeStateMachine
.
Upvotes: 1
Reputation: 72760
This is explained in the first paragraph of Capturing Values:
A closure can capture constants and variables from the surrounding context in which it is defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.
and in a note a few paragraphs below that:
Swift determines what should be captured by reference and what should be copied by value.
So, the closure grabs a reference (and not a copy) of currentState
. Any change to that variable inside the closure is done in the instance defined outside the closure, even if the scope no longer exists (because the makeStateMachine
function has been executed).
Upvotes: 4