[swift-evolution] [Draft] @selfsafe: a new way to avoid reference cycles

David Hart david at hartbit.com
Sun Feb 19 10:30:34 CST 2017


Thanks for reply Mathew. Here are some more comments:

> On 19 Feb 2017, at 15:51, Matthew Johnson <matthew at anandabits.com> wrote:
> 
> 
> 
> Sent from my iPad
> 
>> On Feb 19, 2017, at 7:41 AM, David Hart <david at hartbit.com> wrote:
>> 
>> I must admit I find this proposal very weird.
> 
> I am going to remove the `withWeakSelf` property.  This conversion can be handled behind the scenes as an implementation detail of passing an argument to a parameter that includes the `selfsafe` annotation.  Hopefully it feels less weird after I do that.
> 
>> 
>> • it only handles strong references to self. While the APIs we work with mostly direct us towards accidental references cycles including self in closures, I would want a compiler feature to be much more generic.
> 
> How would such a feature work?  We already have special case handling for strong self capture by escaping closures in the language.  I don't know of a way to do it more generally in a way that a library could meaningfully take advantage of.  That said, I'm interested in hearing ideas if you have them.

Are you talking about the fact that the language forces us to explicitly prefix member access in escaped closures by 'self.'? If that is the case, it's true that it is a special case handling, but only a syntax feature to make the strong reference stand out, not a semantic difference. And it's the semantic difference that you propose to introduce with 'self' and not with other strong captures that worry me.

>> • I'm not a fan of "magically" fixing reference cycles in certain APIs. It creates special cases, inconsistencies this will create will make it that much worse for newcomers to understand reference cycles and for advanced users to reasons about reference cycles (always having to check the API to check if it handles this special magic).
> 
> How do you feel about the Apple frameworks moving to weak callback semantics for many of their APIs?  Everyone I've talked to *likes* this.  Let's enable them to be implemented and used in a way that is more at home in Swift.

> Would you feel better if we used a sigil at call sites like we do with `inout`?  This would make it clear in the calling code that this semantic is in effect and would also make it clear when it is not in effect.  If users tried to use an API incorrectly they would get a compiler error.

It might help, but I would still have reserve on the balance between the the usefulness this provides on one side against the cognitive weigh of the feature by introducing a semantic inconsistency between references to self and strong references to other variables which can also create reference cycles.

>> On 19 Feb 2017, at 09:15, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>>>> On Feb 18, 2017, at 5:24 PM, Matthew Johnson via swift-evolution <swift-evolution at swift.org> wrote:
>>>> 
>>>> 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.
>>> 
>>> Both of these mechanisms are weirdly ad hoc. They involve the callee assuming things about the caller that are not necessarily correct—in particular, that the caller's `self` is going to, directly or indirectly, hold a strong reference to the callee's `self`.
>>> 
>>> For instance, suppose you've read too many design pattern books, and you're using the Command Pattern:
>>> 
>>>  class DeleteRecordCommand: Command {
>>>      let record: Record
>>> 
>>>      func execute(with viewController: RecordViewController) {
>>>          let alert = UIAlertController(title: "Really delete?", preferredStyle: .alert)
>>> 
>>>          alert.addAction(UIAlertAction(title: "Delete", style: .destructive) { _ in
>>>              self.record.delete()
>>>              viewController.performSegue(withIdentifier: "Cancel", sender: self)
>>>          })
>>>          alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
>>> 
>>>          viewController.present(alert)
>>>      }
>>>  }
>>> 
>>> Now, imagine that the `UIAlertAction` initializer used `@selfsafe`, hoping to prevent incorrect use of `self`. Well, that would be totally wrong in this case—it would weaken `self`, which *needs* to be strong, and leave `viewController` strong, when it's creating a retain cycle. `@selfsafe` didn't prevent a bug—it introduced another one, without any visible sign of it in the code.
>>> 
>>> *The problem is not `self`.* The problem is that you need to pay attention to memory management in Swift. And that's a tradeoff that's baked into the language.
>>> 
>>> -- 
>>> Brent Royal-Gordon
>>> Architechies
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
> 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170219/437bb476/attachment.html>


More information about the swift-evolution mailing list