> On Jun 27, 2016, at 2:51 PM, Russ Bishop via swift-evolution 
> <[email protected]> wrote:
> 
>> 
>> On Jun 27, 2016, at 12:35 AM, Christopher Kornher <[email protected] 
>> <mailto:[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.

I took a quick look at C++ capture lists. Yeah, we don’t want those. But 
another default behavior for captures does make sense for Swift I think. More 
to come.

>> 
>> 
>>> 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.

 Not in the iOS programming that I do most of the time, but I am sure that the 
is often the case for other types of development. I rarely use object 
references in @noescape closures, but styles differ. 

> I don’t see how having them default to weak is a good thing in any capacity.

After thinking about it, i agree. @noescape usages of closures should capture 
strongly. 

> Once we agree on that anything else but strong capture by default will by 
> necessity introduce a cognitive burden.

When closures are used to define UI behaviors, capturing weak is a very 
reasonable default. When GUI elements go away, the reason for the behaviors 
usually goes with them. This is the context that inspired this. 

> 
> 
>> 
>>> 
>>> 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] <mailto:[email protected]>
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to