[swift-users] Capturing structs by reference
Tyler Fleming Cloutier
cloutiertyler at aol.com
Sun Jul 24 04:07:24 CDT 2016
The Swift Programming Language book states:
"Reference counting only applies to instances of classes. Structures and enumerations are value types, not reference types, and are not stored and passed by reference.”
However consider the following example.
func makeIncrementer() -> (() -> Int, () -> Int) {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += 1
return runningTotal
}
func incrementer2() -> Int {
runningTotal += 1
return runningTotal
}
return (incrementer, incrementer2)
}
let x = makeIncrementer()
x.0() // 1
x.1() // 2
Clearly runningTotal is captured by reference by both incrementer and incrementer2. Is closure capturing the only case in which value types are treated as reference types?
Why wouldn’t Swift be implement so that runningTotal was Captured as a static copy at the time of capture so that each of the incrementer functions has their own “value”?
It seems like you could pretty easily run into a retain cycle with a struct even though it is a value type!
Consider:
struct MyValueType {
var x: () -> ()
init() {
self.x = {
print(self)
}
}
}
One might imagine that the capture of a value type like MyValueType would make a static copy of self for the closure, but if I understand correctly I actually just get a retain cycle. But it’s even worse, because (as I understand it) whether I do or not is optimization dependent!
"As an optimization, Swift may instead capture and store a copy of a value if that value is not mutated by a closure, and if the value is not mutated after the closure is created.”
Now it turns out that as of SE-0035 I get an error for the above code. Namely,
“Closure cannot implicitly capture a mutating self parameter.”
Kind of a strange error message for two reasons. The first is that nothing appears to be doing any mutating or declaring an intention of mutating. The second is that it’s not clear at all (to me at least) how to go about remedying the issue.
If I capture self explicitly with something like [s = self], am I getting a copy of self or a reference to self? I would assume a copy of self, but that’s not super clear given the somewhat surprising behavior of capturing value types by reference.
I would think the following would be a valid solution. Is there a better one?
struct MyValueType {
var x: (() -> ())!
init() {
self.x = nil
self.x = { [s = self] in
print(s)
}
}
}
Is there a way to use currying to be more explicit about the semantics of passing a value into a closure?
Any help or discussion would be much appreciated!
Tyler
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160724/ec7d1554/attachment.html>
More information about the swift-users
mailing list