Macondo
Macondo

Reputation: 369

Reference type in Swift - reference to a function/closure

I noticed that in Swift, when I create an originalFunction() with a return value returnValue, and make a new function let referenceA = originalFunction(), this will happen:

  1. Because referenceA is a reference to originalFunction(), when I do let referenceB = referenceA , referenceB and referenceA will share the returnValue.
  2. But when I do let referenceC = originalFunction(), in which case I suppose referenceC and referenceA should also share the returnValue since they both refer to originalFunction(), this is not true.

Why?

Example:

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

//then let's make referenceA    

let incrementByTen = makeIncrementor(forIncrement:10)    
incrementByTen()    
//returns 10    
incrementByTen()    
//returns 20    

//Now make referenceB    
let incrementBy10 = incrementByTen    
//referenceA and referenceB will share the *returnValue*:    
incrementBy10()    
//returns 30    

//Now make referenceC    
let incrementByTen10 = makeIncrementor(forIncrement:10)    
//referenceA and referenceC do not share the *returnValue*    
incrementByTen10()    
//returns 10    

Upvotes: 4

Views: 1341

Answers (2)

Marcus
Marcus

Reputation: 828

Your makeIncrementor function creates a new () -> Int incrementor function that captures the runningTotal variable that you create right above it. Because closures are reference types when you assign your incrementByTen closure to the new incrementBy10 closure, you are really just assigning a reference and each of these vars are pointing to the same closure, so calling either of these will increment the same runningTotal var that the closure captured.

When you call makeIncrementor a second time, it creates a new closure that captures a new runningTotal var, so it does not share the same runningTotal with the first closure you created.

Your incrementor func is not shared because you declare it inside of makeIncrementor, so it is only alive for the scope of that calling of makeIncrementor and will be redeclared as a new func the next time makeIncrementor is called. If you wanted this to be shared every time you called makeIncrementor, your incrementor func would need to be declared outside of makeIncrementor.

Upvotes: 4

findall
findall

Reputation: 2193

If my understanding is correct, this is because nested functions are a mere syntactic sugar to create closures, so another instance of incrementor is created every time makeIncrementor is called.

Your code above is nearly identical to this.

func makeIncrementor(forIncrement amount:Int) -> () -> Int {    
    var runningTotal = 0     
    let incrementor = {    
        runningTotal += amount    
        return runningTotal    
    }    
    return incrementor    
}

Upvotes: 0

Related Questions