<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div style="font-family: HelveticaNeue;" class=""><blockquote type="cite" class="">Can you explain what is so evil about func evil() when it is called from an asynchronously-executed closure?</blockquote></div><div style="font-family: HelveticaNeue;" class=""><br class=""></div><div style="font-family: HelveticaNeue;" class="">Apologies for earlier brevity, perhaps it would be helpful for me to present a more complete, realistic example. Paste the following into main.swift:</div><div style="font-family: HelveticaNeue;" class=""><br class=""></div><blockquote class="" style="font-family: HelveticaNeue; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="">import Foundation</div><div class=""><br class=""></div><div class="">print("Hello, World!")</div><div class=""><br class=""></div><div class="">typealias evilArg = [String:String]</div><div class="">var strongReference: evilArg! = nil</div><div class="">func evil(foo:evilArg ) {</div><div class=""> strongReference = foo</div><div class="">}</div><div class=""><br class=""></div><div class="">final class Photo {</div><div class=""> var data = [UInt8](count: 100000000, repeatedValue: 0) //a large amount of data</div><div class=""> let metadata: [String: String] = [:] //a small amount of data</div><div class=""> func save() {</div><div class=""> dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {</div><div class=""> evil(self.metadata)</div><div class=""> }</div><div class=""> }</div><div class="">}</div><div class="">let p = Photo()</div><div class="">p.save()</div><div class="">//leaks Photo, data, and metadata</div><div class=""><br class=""></div><div class="">let sema = dispatch_semaphore_create(0)</div><div class="">dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)</div></blockquote><div style="font-family: HelveticaNeue;" class=""><br class=""></div><div class="" style="font-family: HelveticaNeue;">In this example, the memory usage at the end of the program is 100MB:</div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;"><img apple-inline="yes" id="197FDD80-DC75-4FC4-AB25-606B425EDA63" height="210" width="258" apple-width="yes" apple-height="yes" src="cid:F82AC3D2-D8A5-4366-8545-4EEE3ADA7BD9@austin.rr.com" class=""></div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;">This is because Photo, data, and metadata are all leaked by the evil function.</div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;">This is the (surprising?) behavior specified in the Swift Book:</div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;"><blockquote type="cite" class="">[A capture occurs when] the closure’s body accesses a property of the instance, such as self.someProperty, or because the closure calls a method on the instance, such as self.someMethod(). In either case, these accesses cause the closure to “capture” self, creating a strong reference cycle.<br class=""></blockquote></div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;">Even though evil may seem (to the casual programmer who does not read language specifications for funsies) like the closure captures only the evil argument `metadata`, it *<b class="">actually</b>* captures <b class="">Photo (and therefore data)</b></div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;">The capture of Photo (data) is somewhat clear when we write</div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><blockquote class="" style="font-family: HelveticaNeue; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="">evil(self.metadata)</div><div class=""><br class=""></div></blockquote><span style="font-family: HelveticaNeue;" class="">But it is hidden when we write</span><div class="" style="font-family: HelveticaNeue;"><br class=""></div><blockquote class="" style="font-family: HelveticaNeue; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="">evil(metadata)</div></blockquote><br class="" style="font-family: HelveticaNeue;"><div class="" style="font-family: HelveticaNeue;">As you propose.</div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;">I think that if we are going to have semantics that capture Photo (data), it had better look like it in a cursory inspection. The existing syntax is not as great as it could be, but it provides a clue. I think even that the existing syntax isn't good enough, because I expect that many people are unaware of this particular dark corner. As you say:</div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;"><blockquote type="cite" class="">Can you explain what is so evil about func evil() when it is called from an asynchronously-executed closure? I don't see an obvious bug here.</blockquote><br class=""></div><div class="" style="font-family: HelveticaNeue;">It may very well be that there is no *obvious* bug, and so what we may actually need is a proposal to make the programmer even more explicit when referencing self, not less.</div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;">But in any case. For `strong self` to make sense, we would need to do one of two things:</div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;">1. We could change Swift semantics to only capture metadata in this example, however this is a breaking change, and a very very nontrivial one. I do not know why it is specified this way in the first place, perhaps a designer can weigh in on that. I do know that ObjC is very similar, so there may be compatibility implications.</div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;">2. We could introduce additional syntax to provide compiler diagnostics to guard in this case, e.g.</div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><blockquote class="" style="font-family: HelveticaNeue; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="">func lessEvil(@noescape foo:evilArg ) { //@noescape currently not supported for non-closure parameters</div><div class=""> self.strongReference = foo //should generate diagnostic about escaping a @noescape parameter</div><div class="">}</div><div class=""><br class=""></div></blockquote><span style="font-family: HelveticaNeue;" class="">and then</span><br class="" style="font-family: HelveticaNeue;"><blockquote class="" style="font-family: HelveticaNeue; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><br class=""></div><div class=""><div class="">dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) { [strong self] in</div><div class=""> evil(metadata) //should generate diagnostic that self is required for functions without @noescape</div><div class=""> lessEvil(metadata) //no diagnostic since parameter is @noescape</div><div class="">}</div></div></blockquote><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;">I think both of these fixes to the proposal are fairly impractical, but they would weaken my vote to -0.5.</div></body></html>