Understanding how multiple closures capture the same value

Hello, I have a question regarding how exactly does Swift handle closure capture context when 2 closures capture the same instance of a value type, in this example string.

struct someStruct {
    func someFunction() {
        var someVariable = "some variable"
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            someVariable = someVariable + " mutated" // mutates captured value type
        }
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            print(someVariable) // prints "some variable mutated"
        }
    }
}

someStruct().someFunction()

My assumption ( based on that comment ) is that both closures share the same closure context from their parent scope.

Could you please share some resources that can help with that question?

Additionally, I have two more questions:

  1. When does the variable ‘someVariable’ get deallocated from the stack?
  2. How does it get shared between two closures?
1 Like

I'd recommend you to consider a simpler example with Int instead of String. Int is a pure simple value type so the analysis won't involve having to deal with all of these:

  • a separate heap allocated object for the string contents
  • COW
  • small string optimisation (strings up to 15 bytes stored inline)

With a simpler Int:

someVariable will not be allocated on the stack in this case but on the heap. If you want to drill to how exactly this is played out in memory - you'd need to start with a closure:

struct Closure {
    var functionPointer: UnsafeRawPointer
    var closureContext: AnyObject?
}

e.g. define your own

func foo(_ closure: @escaping () -> Void) {
    // dump closure bytes to see its layout #2
    closure()
}

and call it similarly to how you call dispatch queue:

    func someFunction() {
        var someVariable = 0x123456789ABCDEF0
        // dump the address of someVariable here #1
        foo {
            someVariable += 1
        }
    }

I bet at some point you'd see the address of the variable obtained in #1 while analysing #2.

3 Likes