> On Jun 27, 2016, at 12:35 AM, Christopher Kornher <[email protected]> wrote:
> 
> 
>> On Jun 26, 2016, at 4:25 PM, Russ Bishop <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>> 
>>> On Jun 26, 2016, at 12:10 PM, Christopher Kornher via swift-evolution 
>>> <[email protected] <mailto:[email protected]>> wrote:
>>> 
>>> I may be too late for Swift 3, but I am planning to propose changes to the 
>>> default behavior for closures capturing object references. The introduction 
>>> of Swift Playgrounds has raised the importance of simplifying the coding of 
>>> leak-free, crash-free closures. New developers should not have to 
>>> understand closure memory management to start writing useful and correct 
>>> code.
>>> 
>>> The topic of the closure weak/strong dance has been discussed on this list 
>>> before. This proposal differs from previous proposals in that it will 
>>> eliminate the dance altogether by default. I am very interested in hearing 
>>> others’ opinions as to whether the benefits outweigh the costs of various 
>>> options.
>> 
>> The problem is that strong reference capture is probably the far more common 
>> case.
> 
> Strong reference capture has not been more common in carefully written code 
> in my experience. Swift is starting to be used for many different problem 
> domains, so your experience may be different. Any examples of real-world code 
> would be greatly appreciated.

In my experience reference cycles are almost always caused by capturing self 
strongly.

> 
> Sometimes closures contain the only references to objects, but this is not 
> common in code that I have seen. It would be extremely rare for strong 
> references to be required for all the references in closure with multiple 
> references (the current default behavior). Long closures can reference many 
> objects and it is all too easy to leave a reference out of the capture list 
> and create a reference cycle. I believe that this pattern should be 
> called-out (see below).
> 
> Strong references are occasionally needed to ensure operations are performed 
> when objects would otherwise be reclaimed, but I have not seen many of these 
> cases. This pattern could be more common in other frameworks. I believe that 
> this pattern should be called-out (see below).
> 
> Multiple capture rules for closures can be supported if desired. The 
> ```[required…``` capture qualifier in the original email is one way todo 
> this. The question mark could be used in a way analogous to `try?` to 
> identify closures using the proposed rules: 
> 
> ```let a:()->Void = {…}?```
> or 
> ``` let a:()->Void = ?{…}```
> etc.
> 
> This would obviously add more complexity but would still be an improvement, I 
> believe.

Possibly, though this inevitably ends up with the C++ lambda rules more or 
less. To put it another way, why would Swift introduce a new way of handling 
this instead of just requiring all closures to specify whether they want strong 
default, weak default, or whatever and completely eliminate any automatic 
behavior? Unfortunately that makes creating closures much more annoying.


> 
> 
>> If you wanted to say that @noescape closures capture references strongly by 
>> default, while escaping closures capture them weakly by default that may be 
>> closer to reasonable for most situations but now you have magic behavior 
>> with an even greater cognitive overhead. (I wonder if it would be more 
>> common that @noescape captures strongly, escaping captures self weak by 
>> default but other objects strongly… of course that would have even worse 
>> cognitive overhead.)
> 
> I did consider treating self differently, but this leads to some very strange 
> cases when delegation, factories and other patterns are considered. 
> 
> This email was implicitly referring to escaping uses of closures. The same 
> closure can be used as escaping or non-escaping. The Swift documentation 
> states:
> 
>  "Marking a closure with @noescape lets the compiler make more aggressive 
> optimizations because it knows more information about the closure’s lifespan."
> 
> @noescape is essentially a hint to the compiler. Optimizers would be free to 
> use strong or unowned references if they can determine that it is safe to do 
> so without altering behavior. 

The majority of all closures are passed to non-escaping functional methods like 
map, filter, etc. I don’t see how having them default to weak is a good thing 
in any capacity. Once we agree on that anything else but strong capture by 
default will by necessity introduce a cognitive burden.


> 
>> 
>> I don’t think there is a way to square this circle. Either you have one 
>> “automagic” behavior that is wrong for some cases (whether strong or weak is 
>> the default), or you require everyone to spam their closures with explicit 
>> capture annotations even if there’s a default “capture everything strongly” 
>> variant (see C++ lambdas).
> 
> Yes, we are discussing tradeoffs. Writing correct code with closures will 
> always require care.I believe that is is better to have safe, leak free code 
> by default than not. I also believe that capturing strong references by 
> default can probably lead to at least as many unexpected behaviors as 
> capturing weak references. I don’t think that many developers would expect, 
> for example, to see zombie view controllers that have not been associated 
> with an active view hierarchy for weeks because a closure is holding on to a 
> strong reference.

I don’t agree that weak by default would equal “safe, leak free”. It might be 
leak-free but it certainly isn’t necessarily safe. In the face of concurrency 
you can’t overlook the “half executed” situation of consecutively doing 
“self?.xyz(); self?.abc()”. Most programmers will assume both xyz() and abc() 
execute or neither execute but that simply isn’t the case. By making weak the 
default capture this existing problem is greatly exacerbated.


Russ
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to