[Proposal] Allow upgrading weak self to strong self by assignment


(E. Maloney) #1

Hello,

I've got a new proposal as an alternative to the one discussed in this thread: Simplified notation for avoiding the [weak self]/strongSelf dance with closures <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160208/009972.html>.

There seems to be almost universal opinion that the pain point described in that proposal proposal is real, however the community seems split on possible solutions.

I'm proposing this new alternative in the hopes that it will garner more support than a new guard capture type.

Link here:

https://gist.github.com/emaloney/4bfcb21aaced15af8884

The text of the proposal follows below.

Evan

···

---

Allow upgrading weak self to strong self by assignment

Proposal: TBD
Author: Evan Maloney <https://github.com/emaloney>
Status: Draft
Review manager: TBD
<https://gist.github.com/emaloney/4bfcb21aaced15af8884#introduction>Introduction

When working with escaping Swift closures, it is a common pattern to capture self weakly to avoid an object reference cycle.

For example, let's say you have a view controller that displays the result of a network operation. When the view controller is placed onscreen, it executes the operation and provides a closure to be executed when the operation completes.

The fact that a network operation may be in-flight should not prevent user from navigating away from that view controller. Similarly, we don't want a pending network operation to prevent our view controller from being deallocated once it goes offscreen. In other words, we only care about the network operation while the view controller is alive; once the view controller has been deallocated, we can safely ignore the result of any network request it initiated.

To achieve this, your networking code might look something like:

networkRequest.fetchData() { [weak self] result in
    guard let strongSelf = self else { return }

    switch result {
    case .Succeeded(let data):
        strongSelf.processData(data)

    case .Failed(let err):
        strongSelf.handleError(err)
    }
}
When it comes time to execute this closure, the guard statement effectively asks the question, "Is the view controller represented by self still alive?" If the answer is no, the guard forces a return and the rest of the closure does not execute.

If self is still alive, then the weakly-captured self will be non-nil and it will be converted into a strong reference held by strongSelf for the duration of the closure's execution.

When the closure is done executing, strongSelf goes away, once again making the view controller represented by selfeligible for deallocation if no other references are held.

<https://gist.github.com/emaloney/4bfcb21aaced15af8884#the-problem>The Problem

The [weak self]/strongSelf dance requires common boilerplate wherever it is used, and the fact that a self-like variable with an arbitrary name adds noise within the closure. The more strongSelf is needed within the closure, the more noise there is. Further, using a consistent name like strongSelf is by convention only; it can't be enforced by the compiler.

<https://gist.github.com/emaloney/4bfcb21aaced15af8884#proposed-solution>Proposed Solution

The proposed solution entails allowing self to be upgraded from a weak reference to a strong reference using assignment.

In any scope where self is a weak reference, the compiler will accept an assignment that upgrades self to a strong reference.

This would allow self to keep its meaningful name instead of being renamed to something arbitrary like strongSelf.

With this feature, the code above could be rewritten as:

networkRequest.fetchData() { [weak self] result in
    guard let self = self else { return }

    switch result {
    case .Succeeded(let data):
        self.processData(data)

    case .Failed(let err):
        self.handleError(err)
    }
}
The following would also be legal:

networkRequest.fetchData() { [weak self] result in
    if let self = self {
        switch result {
        case .Succeeded(let data):
            self.processData(data)

        case .Failed(let err):
            self.handleError(err)
        }
    }
}
As would this:

networkRequest.fetchData() { [weak self] result in
    guard self != nil else { return }

    let self = self!

    switch result {
    case .Succeeded(let data):
        self.processData(data)

    case .Failed(let err):
        self.handleError(err)
    }
}
<https://gist.github.com/emaloney/4bfcb21aaced15af8884#behavior>Behavior

Regardless of which notation is used for this feature, the behavior is the same:

The assignment of the strong self follows the same scoping rules as any other variable.

While the strong self is in scope, it masks the weak self variable. If the strong reference to self goes out of scope before the weak self reference does, the weak self will once again be visible to code.

<https://gist.github.com/emaloney/4bfcb21aaced15af8884#restrictions>Restrictions

To ensure safety, the compiler will enforce certain restrictions on the use of this feature:

Attempting to use this feature in a context where self is not a weak reference to an object will cause a compiler error.

Assignment of self may only be used with let; assigning self to a var is an error. (Because this feature only works with object references and not value types, this restriction does not affect the mutability of self.)

<https://gist.github.com/emaloney/4bfcb21aaced15af8884#impact-on-existing-code>Impact on Existing Code

None, since this does not affect any existing constructs. Implementation of this proposal will not result in any code breakage.

<https://gist.github.com/emaloney/4bfcb21aaced15af8884#alternatives-considered>Alternatives Considered

<https://gist.github.com/emaloney/4bfcb21aaced15af8884#status-quo>Status Quo

The primary alternative is to do nothing, requiring developers to add boilerplate guard code and handle upgrading the weak-to-strong references manually.

As stated above, this leads to needless boilerplate that can easily be factored out by the compiler. Also, the use of a self-like variable with an arbitrary name makes it more difficult to exhaustively find such uses in large projects.

Finally, the need to declare and use alternate names to capture values that already have existing names adds visual clutter to code and serves to obscure the code's original intent, making it harder to reason about.

<https://gist.github.com/emaloney/4bfcb21aaced15af8884#adding-a-new-guard-capture-type>Adding a new guard capture type

An alternate to this proposal involves adding a new capture type, called guard <https://gist.github.com/emaloney/d34ac9b134ece7c60440>, which would automatically handle upgrading self (and other references) from weak to strong.

Although the alternate proposal received a favorable response from the Swift Evolution mailing list, the community seemed split between the approach outlined in that proposal, and the one outlined here.

<https://gist.github.com/emaloney/4bfcb21aaced15af8884#citations>Citations

Variations on this proposal were discussed earlier in the following swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution> threads:

Wanted: syntactic sugar for [weak self] callbacks <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160201/008713.html>
Allowing guard let self = self else { … } for weakly captured self in a closure. <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160201/009023.html>
[Draft Proposal] A simplified notation for avoiding the weak/strong dance with closure capture lists <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160201/009241.html>
[Proposal Update 1] A simplified notation for avoiding the weak/strong dance with closure capture lists <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160208/009972.html>


(plx) #2

Really quickly:

The following would also be legal:
networkRequest.fetchData() { [weak self] result in
    if let self = self {
        switch result {
        case .Succeeded(let data):
            self.processData(data)

        case .Failed(let err):
            self.handleError(err)
        }
    }
}
As would this:

networkRequest.fetchData() { [weak self] result in
    guard self != nil else { return }

    let self = self!

…isn’t there a race condition in this example (admittedly an *unlikely* one in most settings, but still…)?


(E. Maloney) #3

Yes, that's a good point.

Now that I think about it, allowing a standalone `let self =` could never be implemented in a way *guaranteed* to avoid a race condition, so perhaps I should remove it from the proposal altogether.

When I incorporate the next round of feedback, I'll rework the proposal to indicate that it can only be used with `if let` or `guard let`.

···

On Feb 19, 2016, at 2:30 PM, plx via swift-evolution <swift-evolution@swift.org> wrote:

networkRequest.fetchData() { [weak self] result in
    guard self != nil else { return }

    let self = self!

…isn’t there a race condition in this example (admittedly an *unlikely* one in most settings, but still…)?


(Guillaume Lessard) #4

Notwithstanding the third example, I think this is the cleanest way yet presented to do this. No new syntax, no loss of flexibility.

Guillaume Lessard


(Taras Zakharko) #5

Very much in favor of this solution (removing the standalone let self = self!). Its does not introduce any new syntax, its semantics is very obvious, its explicit, and its also much more flexible than the alternative guard capture list proposal while keeping magic to the necessary minimum.

— Taras

···

On 19 Feb 2016, at 20:40, Evan Maloney via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 19, 2016, at 2:30 PM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

networkRequest.fetchData() { [weak self] result in
    guard self != nil else { return }

    let self = self!

…isn’t there a race condition in this example (admittedly an *unlikely* one in most settings, but still…)?

Yes, that's a good point.

Now that I think about it, allowing a standalone `let self =` could never be implemented in a way *guaranteed* to avoid a race condition, so perhaps I should remove it from the proposal altogether.

When I incorporate the next round of feedback, I'll rework the proposal to indicate that it can only be used with `if let` or `guard let`.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Shawn Erickson) #6

I also like this proposal. I wish we could go further in removing the
boilerplate but then you have to start to consider usage scenarios that you
would lose in the process.

For example [guard self] capture option supports one specific situation
without the ability of the block to take alternate actions in the situation
of weak self being nil and also requiring no return blocks. This is great
obviously for that particular situation however it doesn't really help with
the other situations.

This proposal allows for a wide range of possibilities in a language
natural way while reducing the code gyrations we currently do.

···

On Fri, Feb 19, 2016 at 12:21 PM Taras Zakharko via swift-evolution < swift-evolution@swift.org> wrote:

Very much in favor of this solution (removing the standalone let self =
self!). Its does not introduce any new syntax, its semantics is very
obvious, its explicit, and its also much more flexible than the alternative
guard capture list proposal while keeping magic to the necessary minimum.

— Taras

On 19 Feb 2016, at 20:40, Evan Maloney via swift-evolution < > swift-evolution@swift.org> wrote:

On Feb 19, 2016, at 2:30 PM, plx via swift-evolution < > swift-evolution@swift.org> wrote:

networkRequest.fetchData() { [weak self] result in
    guard self != nil else { return }

    let self = self!

…isn’t there a race condition in this example (admittedly an *unlikely*
one in most settings, but still…)?

Yes, that's a good point.

Now that I think about it, allowing a standalone `let self =` could never
be implemented in a way *guaranteed* to avoid a race condition, so perhaps
I should remove it from the proposal altogether.

When I incorporate the next round of feedback, I'll rework the proposal to
indicate that it can only be used with `if let` or `guard let`.

_______________________________________________
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


(Kurt Werle) #7

That's the beauty of it. If you want to do something else, this isn't what
you want. This is just a simple bit of sugar to get rid of the very common
use case where you have a nilable/void callback that you only want executed
if self is not nil.

If you want/need to do something more complicated, then
{ [unowned self] in
  guard self != nil else {
    Do the other thing
  }
}
is great. It's not boilerplate because you're doing something useful in
the else case.

I do still prefer the [unowned self]? syntax, though. It feels so similar
to object?.doSomething(). If the lvalue is nil, you get nothing!

Kurt

···

On Fri, Feb 19, 2016 at 1:39 PM, Shawn Erickson via swift-evolution < swift-evolution@swift.org> wrote:

For example [guard self] capture option supports one specific situation
without the ability of the block to take alternate actions in the situation
of weak self being nil and also requiring no return blocks. This is great
obviously for that particular situation however it doesn't really help with
the other situations.

--
kurt@CircleW.org
http://www.CircleW.org/kurt/


(Shawn Erickson) #8

Oops clicked send by mistake...

I wanted to ponder going one step farther (of course it means modifying the
language a little).

networkRequest.fetchData() { [weak self, weak foo] result in
    guard strong self else { ..., return }
    guard strong foo else { ..., return }
    ...
}

networkRequest.fetchData() { [weak self, weak foo] result in
    if strong self {... if strong foo {...} else {...} ...} else {...}
}

... using strong as an attempt to imply that after the guard I want self
(or foo, etc.) to be a strong reference or in the first part of the if I
want self to be strong.

···

On Fri, Feb 19, 2016 at 1:39 PM Shawn Erickson <shawnce@gmail.com> wrote:

I also like this proposal. I wish we could go further in removing the
boilerplate but then you have to start to consider usage scenarios that you
would lose in the process.

For example [guard self] capture option supports one specific situation
without the ability of the block to take alternate actions in the situation
of weak self being nil and also requiring no return blocks. This is great
obviously for that particular situation however it doesn't really help with
the other situations.

This proposal allows for a wide range of possibilities in a language
natural way while reducing the code gyrations we currently do.

On Fri, Feb 19, 2016 at 12:21 PM Taras Zakharko via swift-evolution < > swift-evolution@swift.org> wrote:

Very much in favor of this solution (removing the standalone let self =
self!). Its does not introduce any new syntax, its semantics is very
obvious, its explicit, and its also much more flexible than the alternative
guard capture list proposal while keeping magic to the necessary minimum.

— Taras

On 19 Feb 2016, at 20:40, Evan Maloney via swift-evolution < >> swift-evolution@swift.org> wrote:

On Feb 19, 2016, at 2:30 PM, plx via swift-evolution < >> swift-evolution@swift.org> wrote:

networkRequest.fetchData() { [weak self] result in
    guard self != nil else { return }

    let self = self!

…isn’t there a race condition in this example (admittedly an *unlikely*
one in most settings, but still…)?

Yes, that's a good point.

Now that I think about it, allowing a standalone `let self =` could never
be implemented in a way *guaranteed* to avoid a race condition, so perhaps
I should remove it from the proposal altogether.

When I incorporate the next round of feedback, I'll rework the proposal
to indicate that it can only be used with `if let` or `guard let`.

_______________________________________________
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


(Shawn Erickson) #9

I get that :slight_smile: but I think it would be helpful to go beyond the no-op case
and help solve the "strongify" situation that exists in the larger problem
domain.

The "strongify" issue – to me – is mostly about avoiding the need to rename
the captured var in the block to allow for the reference to become a strong
reference. I feel it would be great to tackle that for more then the no-op
case.

In my experience I have had what once was "a simple no-op on nil case" turn
into "if nil do some book keeping and no-op the rest" often enough to
desire a broader solution.

···

On Fri, Feb 19, 2016 at 2:03 PM Kurt Werle <kurt@circlew.org> wrote:

On Fri, Feb 19, 2016 at 1:39 PM, Shawn Erickson via swift-evolution < > swift-evolution@swift.org> wrote:

For example [guard self] capture option supports one specific situation
without the ability of the block to take alternate actions in the situation
of weak self being nil and also requiring no return blocks. This is great
obviously for that particular situation however it doesn't really help with
the other situations.

That's the beauty of it. If you want to do something else, this isn't
what you want. This is just a simple bit of sugar to get rid of the very
common use case where you have a nilable/void callback that you only want
executed if self is not nil.

If you want/need to do something more complicated, then
{ [unowned self] in
  guard self != nil else {
    Do the other thing
  }
}
is great. It's not boilerplate because you're doing something useful in
the else case.

I do still prefer the [unowned self]? syntax, though. It feels so similar
to object?.doSomething(). If the lvalue is nil, you get nothing!

Kurt
--
kurt@CircleW.org
http://www.CircleW.org/kurt/


(Kurt Werle) #10

I get that :slight_smile: but I think it would be helpful to go beyond the no-op case
and help solve the "strongify" situation that exists in the larger problem
domain.

OK - so what's wrong with:

{ [unowned self] in

  guard self != nil else {
    Do the other thing
  }
}

It's basically what you're asking for - an unowned implicitly unwrapped
variable followed by an else statement that takes care of the nil case.
Right?

Kurt

···

On Fri, Feb 19, 2016 at 2:30 PM, Shawn Erickson <shawnce@gmail.com> wrote:
--
kurt@CircleW.org
http://www.CircleW.org/kurt/


(Kurt Werle) #11

And to follow up on my own email, isn't that exactly the flow you want?

First you do
{ [unowned self]? in
  ...
}

Then you realize that you need to deal with the else case. You nuke the ?
and add a guard.
{ [unowned self] in
  guard if unowned self != nil self {
    ...

I mean -- I look at that and it seems clear and easy. You have the ? to
deal with the nil case. You remove it and add the block to deal with the
special nil case. The intention of both seems clear. You added the guard
code when you needed it.

Sign me up!
Kurt

···

On Fri, Feb 19, 2016 at 2:39 PM, Kurt Werle <kurt@circlew.org> wrote:

On Fri, Feb 19, 2016 at 2:30 PM, Shawn Erickson <shawnce@gmail.com> wrote:

I get that :slight_smile: but I think it would be helpful to go beyond the no-op case
and help solve the "strongify" situation that exists in the larger problem
domain.

OK - so what's wrong with:

{ [unowned self] in

  guard self != nil else {
    Do the other thing
  }
}

It's basically what you're asking for - an unowned implicitly unwrapped
variable followed by an else statement that takes care of the nil case.
Right?

Kurt
--
kurt@CircleW.org
http://www.CircleW.org/kurt/

--
kurt@CircleW.org
http://www.CircleW.org/kurt/


(Shawn Erickson) #12

I am talking about when capturing weak. The unowned capture situation is
the simpler variant of weak, one that doesn't happen to exhibit the
gyration of strongifying a weak capture.

In the weak situation you most often want to promote the captured weak
reference to a strong reference for some scope of code. You have to do this
currently by assigning the one or more captured weak references you have to
a differently named strong reference.

Additionally it isn't clear to me how a block with multiple captures would
play in what you are proposing.

If the strongify situation could be improved by allowing a captured weak
reference to be made strong while avoiding the renaming gyration then I
could see that being coupled with the "[weak/unowned foo]? in" no-op case
(assuming folks see enough reason for the no-op case).

-Shawn

···

On Fri, Feb 19, 2016 at 2:47 PM Kurt Werle <kurt@circlew.org> wrote:

And to follow up on my own email, isn't that exactly the flow you want?

First you do
{ [unowned self]? in
  ...
}

Then you realize that you need to deal with the else case. You nuke the ?
and add a guard.
{ [unowned self] in
  guard if unowned self != nil self {
    ...

I mean -- I look at that and it seems clear and easy. You have the ? to
deal with the nil case. You remove it and add the block to deal with the
special nil case. The intention of both seems clear. You added the guard
code when you needed it.

Sign me up!
Kurt

On Fri, Feb 19, 2016 at 2:39 PM, Kurt Werle <kurt@circlew.org> wrote:

On Fri, Feb 19, 2016 at 2:30 PM, Shawn Erickson <shawnce@gmail.com> >> wrote:

I get that :slight_smile: but I think it would be helpful to go beyond the no-op
case and help solve the "strongify" situation that exists in the larger
problem domain.

OK - so what's wrong with:

{ [unowned self] in

  guard self != nil else {
    Do the other thing
  }
}

It's basically what you're asking for - an unowned implicitly unwrapped
variable followed by an else statement that takes care of the nil case.
Right?

Kurt
--
kurt@CircleW.org
http://www.CircleW.org/kurt/

--
kurt@CircleW.org
http://www.CircleW.org/kurt/


(Shawn Erickson) #13

Kurt curious... the "[unowed self]? in" style... is that part of another
proposal? The one I hit on is talking about using "[guard self] in".

···

On Fri, Feb 19, 2016 at 3:08 PM Shawn Erickson <shawnce@gmail.com> wrote:

I am talking about when capturing weak. The unowned capture situation is
the simpler variant of weak, one that doesn't happen to exhibit the
gyration of strongifying a weak capture.

In the weak situation you most often want to promote the captured weak
reference to a strong reference for some scope of code. You have to do this
currently by assigning the one or more captured weak references you have to
a differently named strong reference.

Additionally it isn't clear to me how a block with multiple captures would
play in what you are proposing.

If the strongify situation could be improved by allowing a captured weak
reference to be made strong while avoiding the renaming gyration then I
could see that being coupled with the "[weak/unowned foo]? in" no-op case
(assuming folks see enough reason for the no-op case).

-Shawn

On Fri, Feb 19, 2016 at 2:47 PM Kurt Werle <kurt@circlew.org> wrote:

And to follow up on my own email, isn't that exactly the flow you want?

First you do
{ [unowned self]? in
  ...
}

Then you realize that you need to deal with the else case. You nuke the
? and add a guard.
{ [unowned self] in
  guard if unowned self != nil self {
    ...

I mean -- I look at that and it seems clear and easy. You have the ? to
deal with the nil case. You remove it and add the block to deal with the
special nil case. The intention of both seems clear. You added the guard
code when you needed it.

Sign me up!
Kurt

On Fri, Feb 19, 2016 at 2:39 PM, Kurt Werle <kurt@circlew.org> wrote:

On Fri, Feb 19, 2016 at 2:30 PM, Shawn Erickson <shawnce@gmail.com> >>> wrote:

I get that :slight_smile: but I think it would be helpful to go beyond the no-op
case and help solve the "strongify" situation that exists in the larger
problem domain.

OK - so what's wrong with:

{ [unowned self] in

  guard self != nil else {
    Do the other thing
  }
}

It's basically what you're asking for - an unowned implicitly unwrapped
variable followed by an else statement that takes care of the nil case.
Right?

Kurt
--
kurt@CircleW.org
http://www.CircleW.org/kurt/

--
kurt@CircleW.org
http://www.CircleW.org/kurt/


(Kurt Werle) #14

Kurt curious... the "[unowed self]? in" style... is that part of another
proposal? The one I hit on is talking about using "[guard self] in".

Kenny Leung originally suggested instead of [guard self] (or my earlier
notion of [firm self]) that it be [unowned/weak self]? - which more closely
resembles the intent of object?.method() in that it does exactly the same
kind of thing - whereas [guard self] implies guard, which implies an else
statement and more complexity.

The drawback - as you have pointed out - is what to do with multiple
parameters
[unowned self, some, others]?
What does that do? My (Kenny's) notion is that it implicitly does
if let self = self, some = some, others = others {
  ...
}

What if you want some tricky combination of strong/weak references in that
block that you want to handle, where some may be nil and others not? Yeah,
this would not work for that. But I can count the number of times where I
wanted complex references in a [parameter block] where I did not have to
handle them with various guards/if let's using no hands. Which is to say,
this proposal is specifically for the very common boiler plate where you
want everything not to be nil, you don't want to explicitly unwrap it with
boiler plate code, and you want nothing to happen if something is nil.

While I like the look of [unowned self]? better than [guard self], I'd be
happy enough with either.

Kurt

···

On Fri, Feb 19, 2016 at 3:12 PM, Shawn Erickson <shawnce@gmail.com> wrote:

On Fri, Feb 19, 2016 at 3:08 PM Shawn Erickson <shawnce@gmail.com> wrote:

I am talking about when capturing weak. The unowned capture situation is
the simpler variant of weak, one that doesn't happen to exhibit the
gyration of strongifying a weak capture.

In the weak situation you most often want to promote the captured weak
reference to a strong reference for some scope of code. You have to do this
currently by assigning the one or more captured weak references you have to
a differently named strong reference.

Additionally it isn't clear to me how a block with multiple captures
would play in what you are proposing.

If the strongify situation could be improved by allowing a captured weak
reference to be made strong while avoiding the renaming gyration then I
could see that being coupled with the "[weak/unowned foo]? in" no-op case
(assuming folks see enough reason for the no-op case).

-Shawn

On Fri, Feb 19, 2016 at 2:47 PM Kurt Werle <kurt@circlew.org> wrote:

And to follow up on my own email, isn't that exactly the flow you want?

First you do
{ [unowned self]? in
  ...
}

Then you realize that you need to deal with the else case. You nuke the
? and add a guard.
{ [unowned self] in
  guard if unowned self != nil self {
    ...

I mean -- I look at that and it seems clear and easy. You have the ? to
deal with the nil case. You remove it and add the block to deal with the
special nil case. The intention of both seems clear. You added the guard
code when you needed it.

Sign me up!
Kurt

On Fri, Feb 19, 2016 at 2:39 PM, Kurt Werle <kurt@circlew.org> wrote:

On Fri, Feb 19, 2016 at 2:30 PM, Shawn Erickson <shawnce@gmail.com> >>>> wrote:

I get that :slight_smile: but I think it would be helpful to go beyond the no-op
case and help solve the "strongify" situation that exists in the larger
problem domain.

OK - so what's wrong with:

{ [unowned self] in

  guard self != nil else {
    Do the other thing
  }
}

It's basically what you're asking for - an unowned implicitly unwrapped
variable followed by an else statement that takes care of the nil case.
Right?

Kurt
--
kurt@CircleW.org
http://www.CircleW.org/kurt/

--
kurt@CircleW.org
http://www.CircleW.org/kurt/

--
kurt@CircleW.org
http://www.CircleW.org/kurt/


(Andrew Bennett) #15

A quick note, I'm not sure if it's a hack but you can probably still do
this:

   guard let `self` = self else { return }

It would be good to support this without backticks, I suppose it would be
very special case though. I wonder if you could reassign self as a
different type...

Andrew Bennett

···

On Saturday, 20 February 2016, Kurt Werle via swift-evolution < swift-evolution@swift.org> wrote:

On Fri, Feb 19, 2016 at 3:12 PM, Shawn Erickson <shawnce@gmail.com > <javascript:_e(%7B%7D,'cvml','shawnce@gmail.com');>> wrote:

Kurt curious... the "[unowed self]? in" style... is that part of another
proposal? The one I hit on is talking about using "[guard self] in".

Kenny Leung originally suggested instead of [guard self] (or my earlier
notion of [firm self]) that it be [unowned/weak self]? - which more closely
resembles the intent of object?.method() in that it does exactly the same
kind of thing - whereas [guard self] implies guard, which implies an else
statement and more complexity.

The drawback - as you have pointed out - is what to do with multiple
parameters
[unowned self, some, others]?
What does that do? My (Kenny's) notion is that it implicitly does
if let self = self, some = some, others = others {
  ...
}

What if you want some tricky combination of strong/weak references in that
block that you want to handle, where some may be nil and others not? Yeah,
this would not work for that. But I can count the number of times where I
wanted complex references in a [parameter block] where I did not have to
handle them with various guards/if let's using no hands. Which is to say,
this proposal is specifically for the very common boiler plate where you
want everything not to be nil, you don't want to explicitly unwrap it with
boiler plate code, and you want nothing to happen if something is nil.

While I like the look of [unowned self]? better than [guard self], I'd be
happy enough with either.

Kurt

On Fri, Feb 19, 2016 at 3:08 PM Shawn Erickson <shawnce@gmail.com >> <javascript:_e(%7B%7D,'cvml','shawnce@gmail.com');>> wrote:

I am talking about when capturing weak. The unowned capture situation is
the simpler variant of weak, one that doesn't happen to exhibit the
gyration of strongifying a weak capture.

In the weak situation you most often want to promote the captured weak
reference to a strong reference for some scope of code. You have to do this
currently by assigning the one or more captured weak references you have to
a differently named strong reference.

Additionally it isn't clear to me how a block with multiple captures
would play in what you are proposing.

If the strongify situation could be improved by allowing a captured weak
reference to be made strong while avoiding the renaming gyration then I
could see that being coupled with the "[weak/unowned foo]? in" no-op case
(assuming folks see enough reason for the no-op case).

-Shawn

On Fri, Feb 19, 2016 at 2:47 PM Kurt Werle <kurt@circlew.org >>> <javascript:_e(%7B%7D,'cvml','kurt@circlew.org');>> wrote:

And to follow up on my own email, isn't that exactly the flow you want?

First you do
{ [unowned self]? in
  ...
}

Then you realize that you need to deal with the else case. You nuke
the ? and add a guard.
{ [unowned self] in
  guard if unowned self != nil self {
    ...

I mean -- I look at that and it seems clear and easy. You have the ?
to deal with the nil case. You remove it and add the block to deal with
the special nil case. The intention of both seems clear. You added the
guard code when you needed it.

Sign me up!
Kurt

On Fri, Feb 19, 2016 at 2:39 PM, Kurt Werle <kurt@circlew.org >>>> <javascript:_e(%7B%7D,'cvml','kurt@circlew.org');>> wrote:

On Fri, Feb 19, 2016 at 2:30 PM, Shawn Erickson <shawnce@gmail.com >>>>> <javascript:_e(%7B%7D,'cvml','shawnce@gmail.com');>> wrote:

I get that :slight_smile: but I think it would be helpful to go beyond the no-op
case and help solve the "strongify" situation that exists in the larger
problem domain.

OK - so what's wrong with:

{ [unowned self] in

  guard self != nil else {
    Do the other thing
  }
}

It's basically what you're asking for - an unowned implicitly
unwrapped variable followed by an else statement that takes care of the nil
case. Right?

Kurt
--
kurt@CircleW.org
http://www.CircleW.org/kurt/

--
kurt@CircleW.org
http://www.CircleW.org/kurt/

--
kurt@CircleW.org
http://www.CircleW.org/kurt/


(E. Maloney) #16

IIRC, the fact that this works is accidental and Chris Lattner mentioned that it should be considered a bug.

···

On Feb 19, 2016, at 8:40 PM, Andrew Bennett via swift-evolution <swift-evolution@swift.org> wrote:

A quick note, I'm not sure if it's a hack but you can probably still do this:

   guard let `self` = self else { return }


(Andrew Bennett) #17

Yes, I only learnt about it from Chris Lattner's comment. Great idea to do
it right :slight_smile:

If I remember correctly I think he said not to rely on it because it wasn't
intentional. I'm not sure if he said it was undesirable. I thought it may
be worth mentioning in case you didn't know, and because it may help the
proposal if it had:

   - you can already do `self` = self, but it's not officially supported
   - this formalises that ability, and removes the need for backticks

Also, you may want to mention that this **only** works between `self`
and `[weak
self]`, ie. you cannot do:

guard self = Optional.Some(123) else { ... }

···

On Sat, Feb 20, 2016 at 1:18 PM, Evan Maloney <emaloney@gilt.com> wrote:

> On Feb 19, 2016, at 8:40 PM, Andrew Bennett via swift-evolution < > swift-evolution@swift.org> wrote:
>
> A quick note, I'm not sure if it's a hack but you can probably still do
this:
>
> guard let `self` = self else { return }

IIRC, the fact that this works is accidental and Chris Lattner mentioned
that it should be considered a bug.


(E. Maloney) #18

Thanks for the feedback, Andrew. I will incorporate it in the next draft, to be sent shortly.

Incidentally, I found Chris Lattner's response about assigning `self`, specifically his statement that "this is a compiler bug":

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160118/007425.html

···

On Feb 20, 2016, at 3:55 AM, Andrew Bennett <cacoyi@gmail.com> wrote:

Yes, I only learnt about it from Chris Lattner's comment. Great idea to do it right :slight_smile:

If I remember correctly I think he said not to rely on it because it wasn't intentional. I'm not sure if he said it was undesirable. I thought it may be worth mentioning in case you didn't know, and because it may help the proposal if it had:
you can already do `self` = self, but it's not officially supported
this formalises that ability, and removes the need for backticks
Also, you may want to mention that this *only* works between `self` and `[weak self]`, ie. you cannot do:

guard self = Optional.Some(123) else { ... }

On Sat, Feb 20, 2016 at 1:18 PM, Evan Maloney <emaloney@gilt.com <mailto:emaloney@gilt.com>> wrote:
> On Feb 19, 2016, at 8:40 PM, Andrew Bennett via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> A quick note, I'm not sure if it's a hack but you can probably still do this:
>
> guard let `self` = self else { return }

IIRC, the fact that this works is accidental and Chris Lattner mentioned that it should be considered a bug.


(Pierre Monod-Broca) #19

I like the proposal also.

···

--
Pierre

Le 22 févr. 2016 à 20:16, Evan Maloney via swift-evolution <swift-evolution@swift.org> a écrit :

Thanks for the feedback, Andrew. I will incorporate it in the next draft, to be sent shortly.

Incidentally, I found Chris Lattner's response about assigning `self`, specifically his statement that "this is a compiler bug":

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160118/007425.html

On Feb 20, 2016, at 3:55 AM, Andrew Bennett <cacoyi@gmail.com <mailto:cacoyi@gmail.com>> wrote:

Yes, I only learnt about it from Chris Lattner's comment. Great idea to do it right :slight_smile:

If I remember correctly I think he said not to rely on it because it wasn't intentional. I'm not sure if he said it was undesirable. I thought it may be worth mentioning in case you didn't know, and because it may help the proposal if it had:
you can already do `self` = self, but it's not officially supported
this formalises that ability, and removes the need for backticks
Also, you may want to mention that this *only* works between `self` and `[weak self]`, ie. you cannot do:

guard self = Optional.Some(123) else { ... }

On Sat, Feb 20, 2016 at 1:18 PM, Evan Maloney <emaloney@gilt.com <mailto:emaloney@gilt.com>> wrote:
> On Feb 19, 2016, at 8:40 PM, Andrew Bennett via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> A quick note, I'm not sure if it's a hack but you can probably still do this:
>
> guard let `self` = self else { return }

IIRC, the fact that this works is accidental and Chris Lattner mentioned that it should be considered a bug.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution