Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable capture by closures in Swift and inout parameters

I noticed that when a variable is captured by a closure in Swift, the closure can actually modify the value. This seems crazy to me and an excellent way of getting horrendous bugs, specially when the same var is captured by several closures.

var capture = "Hello captured"
func g(){
    // this shouldn't be possible!
    capture = capture + "!"
}

g()
capture

On the other hand, there's the inout parameters, which allow a function or closure to modify its parameters.

What's the need for inout, even captured variables can already be modified with impunity??!!

Just trying to understand the design decisions behind this...

like image 896
cfischer Avatar asked Feb 02 '15 21:02

cfischer


1 Answers

Variables from an outer scope that are captured aren't parameters to the routine, hence their mutablility is inherited from context. By default actual parameters to a routine are constant (let) and hence can't be modified locally (and their value isn't returned)

Also note that your example isn't really capturing capture since it's a global variable.

var global = "Global"

func function(nonmutable:Int, var mutable:Int, inout returnable:Int) -> Void {
    // global can be modified here because it's a global (not captured!)
    global = "Global 2"

    // nomutable can't be modified
//    nonmutable = 3

    // mutable can be modified, but it's caller won't see the change
    mutable = 4

    // returnable can be modified, and it's caller sees the change
    returnable = 5
}

var nonmutable = 1
var mutable = 2
var output = 3
function(nonmutable, mutable, &output)

println("nonmutable = \(nonmutable)")
println("mutable = \(mutable)")
println("output = \(output)")

Also, as you can see, the inout parameter is passed differently so that it's obvious that on return, the value may be different.

like image 143
David Berry Avatar answered Nov 03 '22 06:11

David Berry