[swift-evolution] An upcoming proposal for simplifying leak free, safe closures.
xenadu at gmail.com
Sun Jun 26 17:25:03 CDT 2016
> On Jun 26, 2016, at 12:10 PM, Christopher Kornher via swift-evolution <swift-evolution at swift.org> 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.
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.)
No matter what, without a garbage collector you are stuck with sub-optimal solutions for fixing reference cycles. I could imagine a language feature that automatically detected trivial cycles (A -> B -> A) but anything more complex just becomes a form of garbage collection anyway.
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).
> Use of ‘unowned’
> I now routinely create closures that capture `self` and other object references as ‘weak’ even if I think that I feel that `unowned ` would be safe. This may not be the absolutely most performant solution, but it is straightforward and robust.
I agree and our team has adopted the rule that use of unowned is not allowed unless the declaration is private and there is profiler proof that it represents a performance problem, and if used warning comments must be placed in the code. Weak is almost never a performance problem and eliminates the risk of a crash, so it is highly preferable to unowned.
I’d go so far as to say unowned should be removed; let the user use Unmanaged<T> if they need to capture an unowned reference. They’re entering expert territory anyway.
> The core proposal:
> Closures capturing object references should automatically capture all object references as weak.
This becomes a form of the Objective-C messages-to-nil-do-nothing problem where you don’t crash but your closure doesn’t do any work (or does half the work!) because the reference(s) are/become nil. It doesn’t save you from reasoning about object lifetime because it is just as easy for the closure to capture the last reference to an object or for the lifetime to differ from the closure lifetime. You’re just trading reference cycles for a different problem.
> 2) Some of the magic in #1 could be eliminated by introducing a new capture type: ‘required’ to specify ‘weak guarded’ captures, allowing the example closure to be written:
This has been debated before. I support the idea of a “required” capture specifier but IIRC the core team was not supportive of the idea because it adds another layer of magic on the existing magic (object deallocated magically means your closure never executes).
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the swift-evolution