Home > Net >  How does this function retain a value - confused
How does this function retain a value - confused

Time:06-23

I'm learning closures... albeit slowly and I have come across the following example which provides an example of how closures 'close over' the variables/constants within their scope. I'll post the code first and ask my question after:

func countingClosure() -> () -> Int {
    var counter = 0
    let incrementCounter: () -> Int = {
        counter  = 1
        return counter
    }
    return incrementCounter
}

let counter1 = countingClosure()
let counter2 = countingClosure()

counter1() // 1
counter2() // 1
counter1() // 2
counter1() // 3
counter2() // 2

I get the function block and can see how it returns the value it does. What is throwing me is how counter1 and counter2 retain their values, or, maybe, how the function retains the value (which I didn't think they could?). Surely every time counter1 or counter2 is called, counter resets to 0 as its declared inside the function?

I know it's right as the code compiles, I just can't understand how the Int value returned by counterClosure function is retained?

CodePudding user response:

If you rename some of your names, perhaps it becomes a bit clearer:

func makeANewAutoIncrementingClosure() -> () -> Int {
    // Initialize a variable, lives on stack initially but...
    var counter = 0

    let incrementingCounterClosure: () -> Int = {
        // counter is captured and its storage is
        // therefore moved from the stack to
        // somewhere that hangs around as long as this function
        // does
        counter  = 1
        return counter
    }

    // Now we return this new closure, which is like
    // [ function ]--attached to its closed over vars--> {counter: 0}
    return incrementingCounterClosure
}

makeANewAutoIncrementingClosure // () -> () -> Int
// is a function that returns a closure that starts out closing over 0

let incr1 = makeANewAutoIncrementingClosure() // () -> Int
  // a function that increments its captured int and returns it

let incr2 = makeANewAutoIncrementingClosure()

incr1() // 1  this does not call makeANewAutoIncrementingClosure, it calls the incr1 function (i.e. the incrementingCounterClosure).  No assignments to 0 involved
incr2() // 1
incr1() // 2
incr1() // 3
incr2() // 2
  • Related