Explicit vs implicit strong capture difference

This example is based on an example in the language reference (section Capture Lists):

class SimpleClass {
    var value: Int = 0
}
var x = SimpleClass()
var y = SimpleClass()
let closure = { [x] in
    print(x.value, y.value)
}

print(isKnownUniquelyReferenced(&x))
print(isKnownUniquelyReferenced(&y))

false
true

I expected both to be false because the closure strongly captures x and y. Why is the second true?

4 Likes
x.value = 1
y.value = 2
closure()     // prints "1 2"

x = SimpleClass()
y = SimpleClass()

x.value = 3
y.value = 4
closure()     // prints "1 4"

I don’t know how it works under the hood, but the closure indeed treats x and y differently.

Explicit captures are always by-value captures, whereas implicit captures will be by-reference if the captured variable is a var. So there's indeed only one reference to the object stored in y (but two references to the variable y itself, one from the activation record for the top-level code and one from the closure), but there are two references to the object stored in x (one from x and one from the closure).

This is a real semantic difference: there are two ways to name the value currently in x, but only one to name the value currently in y.

5 Likes

Thank you. I get it now. It is good to know that explicit strong captures in capture lists are not identical to implicit ones.

I just tried explaining this myself, and ran into a brick wall with the terminology.

"Referring to a variable by value creates a new reference whereas referring to a variable by reference does NOT create a new reference." Very confusing! I think I have the picture in my head, but explaining it in non-jargon terms is impossible!

I think the important thing to understand about this example is that "x" is captured by value (because it's in the capture list) while "y" is captured by reference.

It sounds like x “is” a reference to a class instance, and the closure captures—and thus copies—the value of x, which is to say a reference to a class instance. Thus there are 2 references to that class instance.

Similarly, y “is” also a reference to a class instance, but here the closure captures a reference to y. Thus, there is only one reference to the class instance referenced by y, and there is also a reference to that reference.

Is that right?

3 Likes

Yes, that's right.

2 Likes