The Future Of [weak self] Rebinding

I'm also not a fan of new syntax to sugar around a single use-case. I'd go with Option #1.

1 Like

Maybe this is similar to what @anandabits has in mind, but what if instead of a sugared [guard self] construct, there was a modifier keyword used in closure capture lists to indicate that a given value needs to be guard-unwrapped? For example (strawman syntax) --

doSomething() { [required weak self] in
    self.foo()
}

which would be equivalent to

doSomething() { [weak self] in
    guard let `self` = self else { return }
    self.foo()
}

This could be applied to other captured values too, not just self. Any thoughts?

3 Likes

Should discussion of ideas like [guard self] take place in a different thread, perhaps? It's related but still a bit of an aside from the main issue here, which is whether self should be allowed to be rebound in let/guard statements. That can be considered separately from the bug fix described in the original post and there's a lot of bike-shedding going on that's independent of that issue.

3 Likes

@allevato I think discussion of guarded closures should be moved to a separate thread. I’m out of town right now and will dig up the draft proposal I have when I get back home in a couple days. I’ll post that in a new thread for further discussion.

Even in small projects, I run into writing guard let strongSelf = self else { return } often. Supporting guard let self = self else { return } makes the most sense to me. We have not hesitated to fix bugs in the past, and here, the migration strategy is the mere removal of two characters. Deprecate the backtick-hack thingy it in Swift 4.2 or Swift 5, remove later in favour of the real logical syntax.

A possible [guard self] syntax in the capture list should be discussed independently.

1 Like

Currently, you can write let `anyIdentifier` = 1, and it's accepted. This isn't a hack, it's a general feature which allows keywords (EG: in, default) to be used as argument labels and identifiers.

Sorry, I was specifically referring to the usage of self with backticks as the 'hack'.

Why should we disable this specifically for self, when it works with any other identifier (even when redundant)? Perhaps a warning with a fixit in the short term is sensible, but in the long term, I'm not sure why self needs special-casing like this.

PS: I agree the current behaviour is a bug/hack. I'm just wondering about your suggestion to ‘remove’ this capability once rebinding self is actually allowed.

1 Like

That's fair. The initial post suggested a migration but like you say, it's actually consistent with the rest of the language as is. Just supporting guard let self = self else { return } is enough, and frictionless.

4 Likes

Evan Maloney: Upgrade self from weak to strong

1 Like

This proposal is already merged as SE-0079 with "Deferred" status.

4 Likes

Thank you Chris and everyone who gave their input.

In my original post I include "having to do a migration" as a con in option 1. Luckily some of you pointed out that it's not necessary if self is to be an identifier.

I've made a small change to the parser that enables option 1 and keeps the rest of the compiler behavior for now: [Parse] Enable self rebinding (to self) by dduan · Pull Request #15306 · apple/swift · GitHub

With this patch, self is not completely a normal identifier yet in the sense that the parser would still consider it a keyword sometimes. But it gets us closer.

7 Likes

I will add my :+1: for option #1 because it is what the Swift language naturally pushes developers towards.

While guard let `self` = self else { return } is considered a hack around a compiler bug, one may argue that guard let strongSelf = self else { return } is a hack around a design shortcoming in the language.

Swift is still a nascent language and hasn't hesitated to improve support for best practices that the community has trended towards. I would love to see @anandabits' proposal revived and this issue discussed in even greater depth.

Why not just introduce an unwrap keyword?

guard unwrap self else { ... }
if unwrap self { ... }
5 Likes

:point_up: This is what's always made the most sense to me.

I suggest starting a separate thread for this pitch.

Sorry, I don't agree. The proposed syntax IMO is about unwrapping and shadowing the 'self' variable.

I remember there was a discussion about shadowing in Swift evaluation list, and IIRC the common opinion was that shadowing is a bad practice, that 'if let someVariable = someVariable' is a bad style and you should provide meaningful name for new unwrapped variable.

If the common opinion was changed, and we agree that 'if let something = something' (like 'if let self = self') is a common and useful practice/style - then I don't think we should distinct 'self' variable from any other variable name.

I mean, if we agree shadowing is acceptable style/practice, that is/will be used all the time, we need to improve the developer's live with better solution than 'if let self = self' - which IS confising IMO('self' is a special variable and we assign it to something other)

The above proposed 'unwrap' keyword will solve the initial problem of this thread + helps in all other situations when we shadowing+unwrapping variable:

if let mySomeVariable = mySomeVariable {...}
vs
if unwrap mySomeVariable {..}

guard unwrap someVar else {...}

guard unwrap self else {...}

I think what @duan really meant is to separate the two problems of this thread into standalone pitch threads.

  • Rebinding (this thread)
  • Unwrapping an optional without the need to repreat the name (unwrap keyword)

That's only fair from my point of view.

5 Likes

As @DevAndArtist said, there are multiple proposal being discussed here, I think three at the moment:

  • Allow rebinding self (this thread): which there is already a merged PR here, from @dduan (does that mean that the discussion is finished because the proposal has been accepted and merged?)
  • Unwrapping an optional without the need to repeat the name (unwrap keyword: if unwrap mySomeVariable {…}): there is no updated thread at the moment discussing this, as far as I know. Also, from the Swift evolution repo (here), this proposal seems to be among the "commonly proposed and rejected" ones:
  • The usage of [guard self] in closures returning Void, as syntactic sugar for substituting the commonly used piece of code [weak self] in guard let strongSelf = self else { return }. That has already an active discussion thread here.

Regarding the second point, I'm not sure if a keyword like unwrap was ever proposed. The commonly rejected thing is just if foo or if let foo? and such, but a keyword is no longer just syntactic sugar. There is still a small chance to improve that area, I think.