Copying a closure in Swift

My understanding is that closures are reference types, so doing something like the following will result in both constants referring to the same instance of the closure:

let closureA = { print("I'm in a closure") }
let closureB = closureA

In Obj-C I believe there was a way to make a copy of a block.

Is there a way to make a copy of a closure in Swift?

The copying mechanism in ObjC is just for getting the block off the stack; once itā€™s off the stack, ā€œcopyingā€ just retains the existing value. That detail is something that Swift hides from you.

3 Likes

Closure variables have value semantics. (But are presumably only copyā€onā€write like structures.)

var closure: (Int) -> Void = { print("\($0): Iā€™m still the first closure.") }
closure(1) // 1: Iā€™m still the first closure.

var newVariable = closure
newVariable(2) // 2: Iā€™m still the first closure.

closure = { print("\($0): Iā€™ve been mutated.") }
closure(3) // 3: Iā€™ve been mutated.
newVariable(4) // 4: Iā€™m still the first closure.

On second thought, thatā€™s not really mutation but reassignment.

Since closures arenā€™t mutable in the first place, Iā€™m not sure what difference it makes, or why you would need a copy instead of a reference. What is it you are trying to do?

1 Like

Closures are meant to be blocks of functionality, they don't hold stored state or properties. So I'm also curious what the intention of OP is.

That's not true, they do hold state and that state isn't copied when you copy the closure itself. Check out this snippet:

func giveMeAClosureThatHoldsState() -> ( (Int) -> Int ) {
    var state = 0
    return { difference in
        state += difference
        return state
    }
}

let closureWithState = giveMeAClosureThatHoldsState()
let closureCopy = closureWithState
let anotherClosureWithState = giveMeAClosureThatHoldsState()
print(closureWithState(1)) // prints 1
print(closureWithState(1)) // prints 2
print(closureCopy(1)) // prints 3
print(anotherClosureWithState(1)) // prints 1
2 Likes

As others have explained above, closures don't really copy.

Yet there is a closure feature which is somewhat related: the capture list.

The capture list allows a closure to copy the values of captured variables, and this makes a big difference when captured variables are mutable. Compare:

var value = 0
let closure1 = { return value }
let closure2 = { [value] in return value }
print("closure1: \(closure1())") // prints "closure1: 0"
print("closure2: \(closure2())") // prints "closure2: 0"

value = 42
print("closure1: \(closure1())") // prints "closure1: 42"
print("closure2: \(closure2())") // prints "closure2: 0"

See Documentation for more information.

3 Likes