This places the burden on users.  The library is not able to offer a guarantee.

Sent from my iPad

> On Feb 19, 2017, at 1:20 AM, Derrick Ho <wh1pch...@gmail.com> wrote:
> 
> What wrong with [unowned self]
>> On Sat, Feb 18, 2017 at 11:01 PM Daniel Duan via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> This reminded me of an idea I had long time ago which will have a similar 
>> effect: add a way to disable implicit captures for closures. FWIW.
>> 
>> > On Feb 18, 2017, at 5:24 PM, Matthew Johnson via swift-evolution 
>> > <swift-evolution@swift.org> wrote:
>> >
>> > # `@selfsafe`: a new way to avoid reference cycles
>> >
>> > * Proposal: [SE-NNNN](NNNN-selfsafe.md)
>> > * Authors: [Matthew Johnson](https://github.com/anandabits)
>> > * Review Manager: TBD
>> > * Status: **Awaiting review**
>> >
>> > ## Introduction
>> >
>> > This proposal introduces the `@selfsafe` function argument attribute which 
>> > together with a `withWeakSelf` property on values of function type.  
>> > Together these features enable library authors to create APIs can be 
>> > statically verified to never extend the lifetime of the `self` a function 
>> > they take may have captured.  This is accomplished by allowing the library 
>> > implementation convert the function to a nearly identical function that is 
>> > guaraneteed to have a `weak` capture of `self` and be a no-op after `self` 
>> > is released.
>> >
>> > Swift-evolution thread: []()
>> >
>> > ## Motivation
>> >
>> > Accidentally forgeting to use weak references is a common problem and can 
>> > easily lead to reference cycles.  Some APIs are best designed such that 
>> > users *cannot* extend the lifetime of `self` by escaping a closure that 
>> > happens to strongly capture `self`.  For example, 
>> > `UIControl.addTarget(_:action:for:) does not retain the target, thereby 
>> > preventing users from making the mistake of using a closure with an 
>> > accidental strong reference.  We can do something similar in Swift:
>> >
>> > ```swift
>> > // in the library:
>> > func addTarget<T: AnyObject>(_ target: T, action: T -> Int -> Void) {
>> >   // store a weak reference to the target
>> >   // when the action is fired call ref.map{ action($0)(42) }
>> > }
>> >
>> > // in user code:
>> > class C {
>> >   init() {
>> >      addTarget(self, action: C.takesInt)
>> >   }
>> >
>> >   func takesInt(_ i: Int) {}
>> > }
>> > ```
>> >
>> > Both the library and the caller have to deal with a lot of details and 
>> > boilerplate that we would prefer to avoid.  The natural design in Swift 
>> > would be to simply take an action function.  Unfortunately if we do that 
>> > we run into a problem:
>> >
>> > ```swift
>> > // in the library
>> > func addAction(_ f: Int -> Void) {
>> >   // store a strong ref to f, which might include a strong ref to a 
>> > captured self
>> >   // later when the action is fired call f(42)
>> > }
>> >
>> > // in user code
>> > class C {
>> >   init() {
>> >      addAction(takesInt)
>> >      // oops! should have been: addAction{ [weak self] self?.takesInt($0) }
>> >   }
>> >
>> >   func takesInt(_ i: Int) {}
>> > }
>> > ```
>> >
>> > Here the syntax is much nicer, but unfortunately we have unintentionally 
>> > extended the lifetime of `self`.  The burden of ensuring `self` is not 
>> > captured or captured weakly falls on users of the library.
>> >
>> > It would very nice if it were possible to design an API that has weak 
>> > capture semantics while still acheiving the more concise and Swifty syntax.
>> >
>> > ## Proposed Solution
>> >
>> > This proposal introduces a read-only property on all function types: 
>> > `withWeakSelf` as well as a `@selfsafe` function argument annotation.  
>> > (This name for the annotation is a strawman - I would love to hear better 
>> > ideas)
>> >
>> > ### `withWeakSelf`
>> >
>> > `withWeakSelf` can be imagined as a property declared like the following:
>> >
>> > ```swift
>> > extension T -> Void {
>> >  var withWeakSelf: T -> Void { return // compiler magic }
>> > }
>> > extension T -> U {
>> >  var withWeakSelf: T -> U? { return // compiler magic }
>> > }
>> > extension T -> U? {
>> >  var withWeakSelf: T -> U? { return // compiler magic }
>> > }
>> > ```
>> >
>> > It returns a closure that is identical to itself in every respect except 
>> > four:
>> > 1. If the context includes a strong or unowned `self` capture, that is 
>> > converted to a weak capture.
>> > 2. If the function returns a non-`Void`, non-`Optional` type the return 
>> > type is wrapped in an `Optional`.
>> > 3. The function returned by `withWeakSelf` is a no-op after `self` has 
>> > been released.  If the return type is non-`Void`, the function returns 
>> > `nil` after `self` has been released.
>> > 4. Any addtional non-`self` context is released as soon as possible after 
>> > `self` is released.
>> >
>> > From these rules, it follows that `withWeakSelf` can be a no-op unless 
>> > `self` is captured strong or unowned or the return type is non-`Void` and 
>> > non-`Optional`.
>> >
>> > Important note: any additional context the closure requies beyond `self` 
>> > continues to be captured as it was originally.
>> >
>> > ### `@selfsafe`
>> >
>> > When a function argument is annotated with `@selfsafe` two rules are in 
>> > effect for the implementation:
>> > 1. The argument *is not* allowed to escape the function.
>> > 2. The closure returend by `withWeakSelf` *is* allowed to escape the 
>> > function.
>> >
>> > There should also be a warning if `argument.withWeakSelf` *does not* 
>> > escape the function in any code paths (because the `@selfsafe` annotation 
>> > is meaningless if it does not escape).
>> >
>> > This allows a library to do something like the following (a simplified 
>> > version of a hypothetical future method on `UIControl`):
>> >
>> > ```swift
>> >   class UIControl {
>> >
>> >      var action: () -> Void
>> >
>> >      func setAction(_ action: @selfsafe () -> Void) {
>> >         self.action = action.withWeakSelf
>> >      }
>> >   }
>> > ```
>> >
>> > In the previous example the function declares the argument with the 
>> > `@selfsafe` annotation.  The compiler verifies that the `action` argument 
>> > does not escape `setAction` and that `action.withWeakSelf` *does* escape.  
>> > Because these verifications guarantee that the lifetime of `self` cannot 
>> > be exteneded by calling `setAction`, the compiler can allow users to omit 
>> > `self` if this function is called with a closure.
>> >
>> > ```swift
>> > class UIViewController {
>> >   func viewDidLoad() {
>> >       // misc setup
>> >       myControl.setAction(doSomething) // great! no problem creating a 
>> > reference cycle.
>> >       myOtherControl.setAction {
>> >          // `self.doSomethingElse()` is not required.
>> >          // The compiler knows we cannot create a reference cycle here.
>> >          doSomethingElse()
>> >       }
>> >   }
>> >   func doSomething() {}
>> >   func doSomethingElse() {}
>> > }
>> > ```
>> >
>> > ## Detailed design
>> >
>> > TBD - If anyone can think of additional details that need to be spelled 
>> > out please provide feedback in this thread.
>> >
>> > ## Source compatibility
>> >
>> > No effect.  This is a purely additive change.
>> >
>> > ## Effect on ABI stability
>> >
>> > No effect.  This is a purely additive change.
>> >
>> > ## Effect on API resilience
>> >
>> > No effect.  This is a purely additive change.
>> >
>> >
>> > ## Alternatives considered
>> >
>> > I considered various ways of exposing the entire captured context or the 
>> > captured `self` reference directly as properties of function types, along 
>> > with access to an unbound version of the function.  This turns out to be 
>> > far more complex than necessary to solve the problem this proposal aims to 
>> > solve and doesn't enable any interesting use cases I have thought of.
>> >
>> > _______________________________________________
>> > swift-evolution mailing list
>> > swift-evolution@swift.org
>> > https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to