Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do closures capture values from previous calls?

typealias IntMaker = (Void)->Int

func makeCounter() ->IntMaker{
    var n = 0 // Line A

    func adder()->Integer{
        n = n + 1
        return n 
    }
    return adder
}

let counter1 = makeCounter()

counter1() // returns 1
counter1() // returns 2
counter1() // returns 3

Isn't 'Line A' called each time we call counter1() ? meaning that var n = 0 should be called every time...

Why is that the counter returns different values? Shouldn't they always be returning '1' ?

like image 262
mfaani Avatar asked Jun 15 '16 14:06

mfaani


People also ask

What is capturing values in closures?

Capturing Values. A closure can capture constants and variables from the surrounding context in which it's 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.

How do closures capture references to variables by default?

In Swift, closures capture the variables they reference: variables declared outside of the closure but that you use inside the closure are retained by the closure by default, to ensure they are still alive when the closure is executed.

What is closure capture list?

A capture list is defined after the opening curly brace and before the parameter list and return type of the closure. An element of a capture list is the weak or unowned keyword followed by the reference to a class instance. In this example, we use a capture list to weakly capture self in the closure.

How can closures achieve asynchronous functionality?

An instance of a closure can be passed around your code and executed without any knowledge of its internals. That makes them perfect for asynchronous development. A typical use case is when you specify the code that should execute upon the return of an asynchronous operation, and pass it as its parameters.


2 Answers

Obviously, Line A isn't being called each time counter1 is called.

The sequence of events is:

  • makeCounter is called, which declares and initializes n (Line A), defines adder, and returns adder in a context that includes n already having been defined and initialized to 1.

  • It is this function that was just returned that is assigned to counter1. Because the Line A is not part of that function (adder/counter1), it does not get executed when that function is called.

  • Each call to counter1 is executed in that same context, which is why n retains its value across calls: they are all accessing the same n.

like image 179
Scott Hunter Avatar answered Oct 02 '22 14:10

Scott Hunter


You've called makeCounter() once. That creates your new closure, and assigns it to counter1. This closure closes over the mutable var n, and will remain captured as long as this closure exists.

Calling counter1() will execute it, but it retains the same captured n, and mutates it. This particular "adder" will ALWAYS capture this same n, so long as it exists..

To get the behavior you're suggesting, you need to make new closures which capture new instances of n:

let counter1 = makeCounter()

counter1() // returns 1
counter1() // returns 2
counter1() // returns 3

var counter2 = makeCounter()
counter2() // returns 1
counter2 = makeCounter()
counter2() // returns 1
counter2 = makeCounter()
counter2() // returns 1

Now both counter1 and counter2 each have their own separate instances of n.

like image 32
Alexander Avatar answered Oct 02 '22 16:10

Alexander