[swift-evolution] $self

Jay Abbott jay at abbott.me.uk
Wed Sep 28 19:48:29 CDT 2016


Sean, yeah that's kind of what I was suggesting for @escaping closures - it
should be the default... but it is a breaking change and as Chris pointed
out that would need extreme justification... plus it would be a behaviour
change with no syntax change, so code that was never "upgraded" would be
very difficult to tell the original intention. I like the idea but I don't
know if I can come up with "extreme justification" for it.

On Thu, 29 Sep 2016 at 01:46 Sean Heber <sean at fifthace.com> wrote:

> Now that I think about this, wouldn't that be a better default behavior?
> All captures are this "required" type which means all closures are typed as
> optional. To override that behavior, you'd have to explicitly declare a
> weak or unowned capture instead and if you did that for all reference
> captures, the closure's type would be non-optional as they are now. Seems
> like that'd be safer. I'll shut up now.
>
> l8r
> Sean
>
> Sent from my iPad
>
> On Sep 28, 2016, at 7:25 PM, Sean Heber <sean at fifthace.com> wrote:
>
> Pretty sure this is all way out of scope, but something about this made me
> think about this idea (which maybe isn't unique or is maybe even
> unworkable), but imagine something like where a new capture type is added
> such as "required" (for lack of another name right now). And the way this
> works is similar to unowned, but it makes the entire closure "weak" in such
> a way that the moment any of the required captures go nil, any references
> to that closure instance also effectively become nil.
>
> So modifying the example:
>
> func viewDidLoad() {
>     self.loginForm.onSubmit = {[required self]
>          let f = self.loginForm
>          self.startLoginRequest(email:f.email.text, pwd:f.pwd.text)
>     }
> }
>
> So in this case, "required self" means self is effectively "unowned" but
> any references to this closure would have to be weak optional like: weak
> var onSubmit: (()->Void)? So that when the view controller gets
> deallocated, the closure goes with it and references become nil.
>
> l8r
> Sean
>
> Sent from my iPad
>
> On Sep 28, 2016, at 6:42 PM, Jay Abbott via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> It could potentially be a breaking change if the default for @escaping
> closures were made to be weak-capturing.
>
> Since the weak-capturing pattern is only really desirable for @escaping
> closures, and (I think) it would be the usual preference, could @escaping
> also imply weak-capturing for all references (not just self)? Then there
> would be another syntax for strong-capturing-escaping closures.
> Non-escaping closures could a) strongly capture references; or b) existing
> strong references stay strong and weak ones stay weak, meaning no
> ref-counts need to change at all when passing them.
>
>
> On Thu, 29 Sep 2016 at 00:06 Paul Jack via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>> So previously there were a few threads on the "strong self/weak self
>> dance" but they didn't seem to get anywhere. For instance:
>>
>>
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160201/008713.html
>>
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010759.html
>>
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160208/009972.html
>>
>> ...and possibly others.
>>
>> I'd like to propose something even easier (and more specific) than all
>> of the above discussions. Specifically, I'd like to introduce a new
>> automagic closure variable, $self, whose presence in a closure would
>> cause that closure to weakly capture self in a safe manner.
>>
>> As a concrete example, let's imagine a UIViewController for a login
>> form. Under this proposal, the following code:
>>
>> func viewDidLoad() {
>>     self.loginForm.onSubmit = {
>>          let f = $self.loginForm
>>          $self.startLoginRequest(email:f.email.text, pwd:f.pwd.text)
>>     }
>> }
>>
>> ...would be treated by the compiler as equivalent to:
>>
>> func viewDidLoad() {
>>     self.loginForm.onSubmit = {
>>          [weak self] in
>>          if let selfie = self {
>>              let f = selfie.loginForm
>>              selfie.startLoginRequest(email:f.email.text,
>>              pwd:f.pwd.text)
>>          }
>>     }
>> }
>>
>> Note the "if let" there: If self no longer exists, the closure does not
>> execute at all, but if self does exist, then it exists for the entirety
>> of the execution of the closure (ie, self won't vanish as a side-effect
>> of some statement in the closure.) I think these semantics obey the
>> principle of least surprise; $self can be treated by the developer as a
>> strong reference.
>>
>> However, that does mean that $self can only be used in a closure that's
>> (a) Void or (b) Optional. In the latter case, returning nil when self
>> doesn't exist seems like reasonable/expected behavior.
>>
>> It would be a compile-time error to use both $self and normal self in
>> the same closure.
>>
>> I'd like to keep this simple, meaning $self always does the above and
>> nothing else. So, if you need an unowned self, you still need the
>> original syntax; if your closure needs a non-Optional return type, you
>> still need the original syntax; etc.
>>
>> Thoughts?
>>
>> -Paul
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
> _______________________________________________
> 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/20160929/d88f8461/attachment.html>


More information about the swift-evolution mailing list