[swift-users] Capturing structs by reference

Tyler Fleming Cloutier cloutiertyler at aol.com
Sun Jul 24 18:57:04 CDT 2016


This seems to just raise more questions than it answers. :p

Why would one be allowed but not the other? They should be equivalent.


> On Jul 24, 2016, at 5:49 AM, Zhao Xin <owenzx at gmail.com> wrote:
> 
> Below code works.
> 
> struct MyValueType {
>     
>     var x: () -> () {
>         return { print(self) }
>     }
>     
>     init() {
> //        self.x = {
> //            print(self)
> //        }
>     }
> }
> 
> let a = MyValueType()
> a.x() // MyValueType()
> 
> Zhaoxin
> 
> On Sun, Jul 24, 2016 at 5:11 PM, Tyler Fleming Cloutier via swift-users <swift-users at swift.org <mailto:swift-users at swift.org>> wrote:
> Also if capture lists for structs do capture by value, how can I avoid the newly added error “Closure cannot implicitly capture a mutating self parameter” without changing the original reference semantics of MyValueType?
> 
> Also why can’t I specify weak self for value types in capture lists if a captured value type is really just a reference anyway? What’s the purpose of that?
> 
> 
>> On Jul 24, 2016, at 2:07 AM, Tyler Fleming Cloutier <cloutiertyler at aol.com <mailto:cloutiertyler at aol.com>> wrote:
>> 
>> 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
>> 
>> 
> 
> 
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org <mailto:swift-users at swift.org>
> https://lists.swift.org/mailman/listinfo/swift-users <https://lists.swift.org/mailman/listinfo/swift-users>
> 
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160724/aa39d41f/attachment.html>


More information about the swift-users mailing list