guard let x = x

In your example the keyword only makes sense if you are shadowing the
optional variable. How would unwrap work with a different name?

Ex:
guard let bar = foo else {...}
guard unwrap bar else {...} -> There is no context to what the guard is
unwrapping
This could end up leading to:
guard unwrap bar = foo else {...} which is essentially the same as the
current guard

Alvarado, Joshua

···

On Wed, Oct 26, 2016 at 11:09 AM, Josh Parmenter via swift-evolution < swift-evolution@swift.org> wrote:

On Oct 26, 2016, at 9:37 AM, Chris Lattner via swift-evolution < > swift-evolution@swift.org<mailto:swift-evolution@swift.org>> wrote:

To me, this is the most promising direction, but I’d suggest the use of
“unwrap" as the keyword. If you compare these two:

a) guard let foobar = foobar else { … }
b) guard unwrap foobar else { … }

I think that b) wins by virtue of eliminating repetition ("foobar =
foobar" fails DRY principles), but retains clarity by introducing a word
into the grammar that people already commonly know and use, and which is
googlable if they don’t.

I find b) to be quite convincing.

Best,

Josh

Joshua Parmenter | Engineering Lead, Apple Technologies

T 248 777 7777
C 206 437 1551
F 248 616 1980
www.vectorform.com<http://www.vectorform.com/&gt;

Vectorform
2107 Elliott Ave Suite 303
Seattle, WA 98121 USA

Think Tank. Lab. Studio.
We invent digital products and experiences.

SEATTLE | DETROIT | NEW YORK | MUNICH | HYDERABAD

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

--
Joshua Alvarado
alvaradojoshua0@gmail.com

So I can stop thinking about this. Gist is here: unwrap.md · GitHub

-- E

Introducing unwrap

Proposal: TBD
Author: Erica Sadun <https://github.com/erica&gt;, Chris Lattner <https://github.com/lattner&gt;, David Goodine
Status: TBD
Review manager: TBD
<unwrap.md · GitHub

This proposal introduces unwrap, simplifying common shadowing and allowing a unified syntax for one-item associated values such as Result types.

Swift-evolution thread: guard let x = x <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20161024/028440.html&gt;
<unwrap.md · GitHub

Swift lacks a unified, safe way to bind an optional or single-value enumeration to a shadowed varaiable that is guaranteed to be the same name. Introducing unwrap ensures the conditionally bound item does not accidentally shadow any other item.

Compare:

guard let foobar = foobar else { … }
guard unwrap foobar else { … }
Using unwrap eliminates repetition ("foobar = foobar" fails DRY principles <https://en.wikipedia.org/wiki/Don't_repeat_yourself&gt;\) and retains clarity. The keyword is common, simple to understand, and easy to search for if Swift users are unfamiliar with it.

This syntax simplifies one-item associated value enumerations by offering a common syntax. Compare:

enum Result<T> { case success(T), error(Error) }

guard case let .success(value) = result else { ... }
guard unwrap result else { ... }
In the latter case result is bound to the wrapped value. Again, it is simpler and clearer, even with non-Optional types.

<unwrap.md · GitHub Design

unwrap can be used with any one-value enumeration. The unwrapped value is bound to the same symbol as the associated type.

enum TypeName<T, U> { case anycase(T), anothercase(U) }

// First and second are type `TypeName`
let first = TypeName.anyCase(value1)
let second = TypeName. anothercase(value2)

guard unwrap first else { ... }
// first is now shadowed as type T

guard unwrap second else { ... }
// second is now shadowed as type U
<unwrap.md · GitHub on Existing Code

This change is additive and has no impact on existing code other than intentional refactoring.

<unwrap.md · GitHub

This proposal is additive and not suited for consideration until Swift 4 phase 2

<unwrap.md · GitHub Considered

Using a bind keyword. Past discussions were held in the first week of February 2016 <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160201/thread.html&gt;\.
Fixing pattern matching grammar <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20161024/tbd.html&gt;
Not using this approach

···

On Oct 26, 2016, at 11:39 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 26, 2016, at 10:23 AM, Joshua Alvarado <alvaradojoshua0@gmail.com> wrote:

In your example the keyword only makes sense if you are shadowing the optional variable. How would unwrap work with a different name?

It wouldn’t: “unwrap” would never include an equal sign. If you want to do that, use a standard "if let”.

-Chris

Don't we currently have "for x in y" and "for var x in y"? So, we could
have "unwrap x" and "unwrap var x".

And since unwrap wouldn't allow arbitrary Boolean expressions at the front
like if and guard statements do, it could use the where clause like for
loops do.

···

On Mon, Oct 31, 2016 at 14:58 Pyry Jahkola <pyry.jahkola@iki.fi> wrote:

On 31 Oct 2016, Xiaodi Wu wrote:

An alternative that would seem to satisfy some objections is to have a
distinct "unwrap" statement--as in: "unwrap x else { ... }".

True. The `*let*`, on the other hand, has the minor upside that it's
naturally substituted with `*var*` where in-place mutation is needed:

    *guard let* value, *var* collection *else* { ... }
    collection.append(value)
    // ...

Disclaimer: I don't know if this is a realistic usage scenario but it
seems more natural to Swift, in my view.

— Pyry

You're right. I'd forgotten about that. I found out you can even place the `var` keyword inside a tuple pattern where only one variable is going to be modified locally:

    for (var i, c) in "foobar".characters.enumerated() {
      i += 1 // pretty contrived example
      print(i, c)
    }

— Pyry

···

On 31 Oct 2016, Xiaodi Wu wrote:

Don't we currently have "for x in y" and "for var x in y"? So, we could have "unwrap x" and "unwrap var x".

And since unwrap wouldn't allow arbitrary Boolean expressions at the front like if and guard statements do, it could use the where clause like for loops do.

It seems that we settle on a relatively 'long' keyword 'unwrap',
Did we consider a ? prefix operator?

As we use the ? postfix in order to safely unpack, we could as well introduce prefix ?

guard ?foo, ?bar else { return }

It is 'expressive', and makes me think 'do I have?'.

It is less technically / semantically correct than unwrap, but also gives a playful twist, making those guard/if condition lines more concise.

it would play correctly decently with:

guard var ?foo, var ?bar else { return }

···

--
Florent Vilmart

Le 1 novembre 2016 à 19:08:11, ilya via swift-evolution (swift-evolution@swift.org) a écrit:

a) guard let foobar = foobar else { … }
b) guard unwrap foobar else { … }

I would argue for
c) guard let reallyFoobar = foobar else { … }

(or perhaps guard let foobar_ = foobar else { … } )

That way one can use both an optional foobar and non-optional "unwrapped value of foobar at the moment of guard" without any possibility of mixing those two (and without violating DRY).

Ilya.

On Wed, Oct 26, 2016 at 6:38 PM Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:
On Oct 26, 2016, at 8:58 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:
On Oct 26, 2016, at 5:40 AM, David Goodine via swift-evolution <swift-evolution@swift.org> wrote:

Hey all,

As usual, apologies if this horse was beaten ages ago before I joined the mailing list, but thought I would bring this up.

Yes, this has thoroughly been beaten to death. It is also outside the scope of Swift 4 stage 1. That said, it is such a glaring problem that we’ll have to deal with it at some point.

I was typing the above (for the hundredth time) the other day and I was wondering whether it might be worth considering offering a shorter syntax:

guard let x, y, z else {…}

This specific syntax is commonly requested. The problem with this is that it provides no useful information about what is actually going on: it sacrifices clarity to get terseness, a specific non-goal of Swift.

Erica says:
Your initial suggestion doesn't work as overloading "let" confuses rather than clarifies this process. In February, I brought up `bind x` to mean "conditionally bind x to x, and produce a conditional fail if that's not possible", with the hope that "bind self" could be used in closures. Under that scheme your example would read:

guard bind x, bind y, bind z else { … }

To me, this is the most promising direction, but I’d suggest the use of “unwrap" as the keyword. If you compare these two:

a) guard let foobar = foobar else { … }
b) guard unwrap foobar else { … }

I think that b) wins by virtue of eliminating repetition ("foobar = foobar" fails DRY principles), but retains clarity by introducing a word into the grammar that people already commonly know and use, and which is googlable if they don’t.

This also gives us the conceptual hook to make the “unwrapping an optional” behavior (which occurs with if let, optional chaining, etc) be something that could be extended to other similar user defined types, such as a Result type.

-Chris

_______________________________________________
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

Gonna put in my 2 cents re shadowing being a source of bugs: I use explicit
self everywhere in my codebase and it pairs wonderfully with shadowing,
making the detailed example moot. As far as Dany's message, I think that's
the best way to go forward with an unwrap keyword--just make it work
exactly like if let x = x; not sure what other behavior was being
discussed. Another way to go, though, if we're really worried about
shadowing on mutable properties causing issues, would be to just have
nullity inference on constants, so if you said "let x = someNullableValue;
if x != nil { /* x would be inferred to be non-null here */ }". Kotlin does
this very, very successfully. (But my biggest reservation with such an
implementation in practice, in Kotlin, is that it only works for immutable
properties. Which is why I'm fully +1 on the unwrap statement. People are
going to shadow. Let them do it in a cleaner way.)

···

On Tue, Nov 1, 2016 at 9:47 PM Dany St-Amant via swift-evolution < swift-evolution@swift.org> wrote:

> Le 31 oct. 2016 à 17:44, Erica Sadun via swift-evolution < > swift-evolution@swift.org> a écrit :
>
>
>> On Oct 31, 2016, at 1:51 PM, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>> An alternative that would seem to satisfy some objections is to have a
distinct "unwrap" statement--as in: "unwrap x else { ... }".
>
> I'd be against this alternative as it is doing the work of a guard
statement (including the "must exit scope" rule) with a new keyword and
unneeded redundancy.
>
> Adding "unwrap" is local. It performs one very common task with added
safety (avoids unintended shadow effects) and introduces succinctness and
clarity. In other words, it is a highly focused changed with a measurable
benefit in use.
>
> Compare:
>
> * "Introduce the unwrap statement that acts like guard but is limited to
optionals" creates unnecessary language verbosity.
>
> * "guard x else ", meaning "treat optional values differently than all
other items in a conditional list", fails because it obscures rather than
adds intent. Worse, it would lead to issues with Boolean optionals whose
wrapped value is later used within the same condition.
>
> Xiaodi, you mentioned an alternative approach and I'd love a peek at
what that is.

Also with the 'guard unwrap', the following code make sense:

guard unwrap x, x == 10 else { return }

With a lone unwrap it would not.

unwrap x, x == 10 else { return }

I personally do not like shadowing, but a standalone 'unwrap!' could be of
interest to those loving life in the shadows. Beside the shadowing itself,
it should not be any worst than any of the other '!' usage. The feasibility
of such depends of course on how the compiler manages its variable scoping.

On further thought, if we were to make the, sorry bad word coming,
code-breaking change to disallow legacy shadowing 'let x=x' and force the
shadowing to be done exclusively via this 'unwrap' keyword, it could make
it easier for projects/companies to ban shadowing.

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

If using “unwrap” in itself, then it should be statement that only unwraps, hence the

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: Swiftrien (Rien) · GitHub
Project: http://swiftfire.nl

···

On 02 Nov 2016, at 02:47, Dany St-Amant via swift-evolution <swift-evolution@swift.org> wrote:

Le 31 oct. 2016 à 17:44, Erica Sadun via swift-evolution <swift-evolution@swift.org> a écrit :

On Oct 31, 2016, at 1:51 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

An alternative that would seem to satisfy some objections is to have a distinct "unwrap" statement--as in: "unwrap x else { ... }".

I'd be against this alternative as it is doing the work of a guard statement (including the "must exit scope" rule) with a new keyword and unneeded redundancy.

Adding "unwrap" is local. It performs one very common task with added safety (avoids unintended shadow effects) and introduces succinctness and clarity. In other words, it is a highly focused changed with a measurable benefit in use.

Compare:

* "Introduce the unwrap statement that acts like guard but is limited to optionals" creates unnecessary language verbosity.

* "guard x else ", meaning "treat optional values differently than all other items in a conditional list", fails because it obscures rather than adds intent. Worse, it would lead to issues with Boolean optionals whose wrapped value is later used within the same condition.

Xiaodi, you mentioned an alternative approach and I'd love a peek at what that is.

Also with the 'guard unwrap', the following code make sense:

guard unwrap x, x == 10 else { return }

With a lone unwrap it would not.

unwrap x, x == 10 else { return }

I personally do not like shadowing, but a standalone 'unwrap!' could be of interest to those loving life in the shadows. Beside the shadowing itself, it should not be any worst than any of the other '!' usage. The feasibility of such depends of course on how the compiler manages its variable scoping.

On further thought, if we were to make the, sorry bad word coming, code-breaking change to disallow legacy shadowing 'let x=x' and force the shadowing to be done exclusively via this 'unwrap' keyword, it could make it easier for projects/companies to ban shadowing.

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

How does the compiler decide whether to succeed on anycase or succeed on anothercase respectively? In general, the compiler only statically knows that first & second are of type TypeName, not anything about which case (they could be passed in as function parameters, or returned by an opaque function e.g. `let x = OtherLibrary.returnsTypeName(); guard unwrap x else { … }`), and thus the variant to unwrap has to be chosen based only on that piece of information.

It seems to me that doing this either has to be restricted to enums with an “obvious” choice for unwrapping, like Optional, or rely on a sort of forward-looking type inference that Swift doesn’t currently use to deduce the unwrapped type based on how the value is used later (and I’m not sure that works in all cases, e.g. what if T == U for the TypeName example).

Huon

···

On Oct 28, 2016, at 15:34, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:
<unwrap.md · GitHub Design

unwrap can be used with any one-value enumeration. The unwrapped value is bound to the same symbol as the associated type.

enum TypeName<T, U> { case anycase(T), anothercase(U) }

// First and second are type `TypeName`
let first = TypeName.anyCase(value1)
let second = TypeName. anothercase(value2)

guard unwrap first else { ... }
// first is now shadowed as type T

guard unwrap second else { ... }
// second is now shadowed as type U
<unwrap.md · GitHub;

It succeeds on any one-item case and fails on any non-item case.

-- E

···

On Oct 28, 2016, at 5:00 PM, Huon Wilson <huon@apple.com> wrote:

On Oct 28, 2016, at 15:34, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
<unwrap.md · GitHub Design

unwrap can be used with any one-value enumeration. The unwrapped value is bound to the same symbol as the associated type.

enum TypeName<T, U> { case anycase(T), anothercase(U) }

// First and second are type `TypeName`
let first = TypeName.anyCase(value1)
let second = TypeName. anothercase(value2)

guard unwrap first else { ... }
// first is now shadowed as type T

guard unwrap second else { ... }
// second is now shadowed as type U
<unwrap.md · GitHub;

How does the compiler decide whether to succeed on anycase or succeed on anothercase respectively? In general, the compiler only statically knows that first & second are of type TypeName, not anything about which case (they could be passed in as function parameters, or returned by an opaque function e.g. `let x = OtherLibrary.returnsTypeName(); guard unwrap x else { … }`), and thus the variant to unwrap has to be chosen based only on that piece of information.

It seems to me that doing this either has to be restricted to enums with an “obvious” choice for unwrapping, like Optional, or rely on a sort of forward-looking type inference that Swift doesn’t currently use to deduce the unwrapped type based on how the value is used later (and I’m not sure that works in all cases, e.g. what if T == U for the TypeName example).

+1

Can “unwrap” be used anywhere else?
If not, why not remove the “guard” altogether?
I.e.

unwrap foobar else { … }

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: Swiftrien (Rien) · GitHub
Project: http://swiftfire.nl

···

On 29 Oct 2016, at 00:34, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 26, 2016, at 11:39 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 26, 2016, at 10:23 AM, Joshua Alvarado <alvaradojoshua0@gmail.com> wrote:

In your example the keyword only makes sense if you are shadowing the optional variable. How would unwrap work with a different name?

It wouldn’t: “unwrap” would never include an equal sign. If you want to do that, use a standard "if let”.

-Chris

So I can stop thinking about this. Gist is here: unwrap.md · GitHub

-- E

Introducing unwrap

  • Proposal: TBD
  • Author: Erica Sadun, Chris Lattner, David Goodine
  • Status: TBD
  • Review manager: TBD
Introduction

This proposal introduces unwrap, simplifying common shadowing and allowing a unified syntax for one-item associated values such as Result types.

Swift-evolution thread: guard let x = x

Motivation

Swift lacks a unified, safe way to bind an optional or single-value enumeration to a shadowed varaiable that is guaranteed to be the same name. Introducing unwrap ensures the conditionally bound item does not accidentally shadow any other item.

Compare:

guard let foobar = foobar else { …
}

guard unwrap foobar else { … }
Using unwrap eliminates repetition ("foobar = foobar" fails DRY principles) and retains clarity. The keyword is common, simple to understand, and easy to search for if Swift users are unfamiliar with it.

This syntax simplifies one-item associated value enumerations by offering a common syntax. Compare:

enum Result<T> { case success(T), error(Error
) }

guard case let .success(value) = result else { ...
}

guard unwrap result else { ... }
In the latter case result is bound to the wrapped value. Again, it is simpler and clearer, even with non-Optional types.

Detailed Design

unwrap can be used with any one-value enumeration. The unwrapped value is bound to the same symbol as the associated type.

enum TypeName<T, U> { case anycase(T), anothercase(U) }

// First and second are type `TypeName`
let first = TypeName.anyCase(value1)
let second = TypeName. anothercase(value2)

guard unwrap first else { ... }
// first is now shadowed as type T

guard unwrap second else { ... }
// second is now shadowed as type U

Impact on Existing Code

This change is additive and has no impact on existing code other than intentional refactoring.

Timeline

This proposal is additive and not suited for consideration until Swift 4 phase 2

Alternatives Considered

  • Using a bind keyword. Past discussions were held in the first week of February 2016.
  • Fixing pattern matching grammar
  • Not using this approach

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

Why have the “unwrap” keyword at all? Isn’t “guard” the keyword?

guard blah else {
}

-Kenny

···

On Oct 28, 2016, at 3:34 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 26, 2016, at 11:39 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 26, 2016, at 10:23 AM, Joshua Alvarado <alvaradojoshua0@gmail.com> wrote:

In your example the keyword only makes sense if you are shadowing the optional variable. How would unwrap work with a different name?

It wouldn’t: “unwrap” would never include an equal sign. If you want to do that, use a standard "if let”.

-Chris

So I can stop thinking about this. Gist is here: unwrap.md · GitHub

-- E

Introducing unwrap

  • Proposal: TBD
  • Author: Erica Sadun, Chris Lattner, David Goodine
  • Status: TBD
  • Review manager: TBD
Introduction

This proposal introduces unwrap, simplifying common shadowing and allowing a unified syntax for one-item associated values such as Result types.

Swift-evolution thread: guard let x = x

Motivation

Swift lacks a unified, safe way to bind an optional or single-value enumeration to a shadowed varaiable that is guaranteed to be the same name. Introducing unwrap ensures the conditionally bound item does not accidentally shadow any other item.

Compare:

guard let foobar = foobar else { …
}

guard unwrap foobar else { … }
Using unwrap eliminates repetition ("foobar = foobar" fails DRY principles) and retains clarity. The keyword is common, simple to understand, and easy to search for if Swift users are unfamiliar with it.

This syntax simplifies one-item associated value enumerations by offering a common syntax. Compare:

enum Result<T> { case success(T), error(Error
) }

guard case let .success(value) = result else { ...
}

guard unwrap result else { ... }
In the latter case result is bound to the wrapped value. Again, it is simpler and clearer, even with non-Optional types.

Detailed Design

unwrap can be used with any one-value enumeration. The unwrapped value is bound to the same symbol as the associated type.

enum TypeName<T, U> { case anycase(T), anothercase(U) }

// First and second are type `TypeName`
let first = TypeName.anyCase(value1)
let second = TypeName. anothercase(value2)

guard unwrap first else { ... }
// first is now shadowed as type T

guard unwrap second else { ... }
// second is now shadowed as type U

Impact on Existing Code

This change is additive and has no impact on existing code other than intentional refactoring.

Timeline

This proposal is additive and not suited for consideration until Swift 4 phase 2

Alternatives Considered

  • Using a bind keyword. Past discussions were held in the first week of February 2016.
  • Fixing pattern matching grammar
  • Not using this approach

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

Sorry for piling onto the bikeshed. We do already have a notation for testing that an Optional isn't nil, `x != nil`. We could theoretically bless `<decl ref> != nil` as a statement condition to also unwrap the referenced declaration in the scope guarded by the condition. (`<decl ref> is T` could similarly rebind a declaration as the cast type.)

-Joe

···

On Oct 28, 2016, at 3:34 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 26, 2016, at 11:39 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 26, 2016, at 10:23 AM, Joshua Alvarado <alvaradojoshua0@gmail.com> wrote:

In your example the keyword only makes sense if you are shadowing the optional variable. How would unwrap work with a different name?

It wouldn’t: “unwrap” would never include an equal sign. If you want to do that, use a standard "if let”.

-Chris

So I can stop thinking about this. Gist is here: unwrap.md · GitHub

-- E

Introducing unwrap

  • Proposal: TBD
  • Author: Erica Sadun, Chris Lattner, David Goodine
  • Status: TBD
  • Review manager: TBD
Introduction

This proposal introduces unwrap, simplifying common shadowing and allowing a unified syntax for one-item associated values such as Result types.

Swift-evolution thread: guard let x = x

Motivation

Swift lacks a unified, safe way to bind an optional or single-value enumeration to a shadowed varaiable that is guaranteed to be the same name. Introducing unwrap ensures the conditionally bound item does not accidentally shadow any other item.

Compare:

guard let foobar = foobar else { …
}

guard unwrap foobar else { … }
Using unwrap eliminates repetition ("foobar = foobar" fails DRY principles) and retains clarity. The keyword is common, simple to understand, and easy to search for if Swift users are unfamiliar with it.

This syntax simplifies one-item associated value enumerations by offering a common syntax. Compare:

enum Result<T> { case success(T), error(Error
) }

guard case let .success(value) = result else { ...
}

guard unwrap result else { ... }
In the latter case result is bound to the wrapped value. Again, it is simpler and clearer, even with non-Optional types.

Detailed Design

unwrap can be used with any one-value enumeration. The unwrapped value is bound to the same symbol as the associated type.

enum TypeName<T, U> { case anycase(T), anothercase(U) }

// First and second are type `TypeName`
let first = TypeName.anyCase(value1)
let second = TypeName. anothercase(value2)

guard unwrap first else { ... }
// first is now shadowed as type T

guard unwrap second else { ... }
// second is now shadowed as type U

Impact on Existing Code

This change is additive and has no impact on existing code other than intentional refactoring.

Timeline

This proposal is additive and not suited for consideration until Swift 4 phase 2

Alternatives Considered

  • Using a bind keyword. Past discussions were held in the first week of February 2016.
  • Fixing pattern matching grammar
  • Not using this approach

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

Please ignore, the mail was sent in error.

···

On 02 Nov 2016, at 07:13, Rien via swift-evolution <swift-evolution@swift.org> wrote:

If using “unwrap” in itself, then it should be statement that only unwraps, hence the

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: Swiftrien (Rien) · GitHub
Project: http://swiftfire.nl

<unwrap.md · GitHub Design

unwrap can be used with any one-value enumeration. The unwrapped value is bound to the same symbol as the associated type.

enum TypeName<T, U> { case anycase(T), anothercase(U) }

// First and second are type `TypeName`
let first = TypeName.anyCase(value1)
let second = TypeName. anothercase(value2)

guard unwrap first else { ... }
// first is now shadowed as type T

guard unwrap second else { ... }
// second is now shadowed as type U
<unwrap.md · GitHub;

How does the compiler decide whether to succeed on anycase or succeed on anothercase respectively? In general, the compiler only statically knows that first & second are of type TypeName, not anything about which case (they could be passed in as function parameters, or returned by an opaque function e.g. `let x = OtherLibrary.returnsTypeName(); guard unwrap x else { … }`), and thus the variant to unwrap has to be chosen based only on that piece of information.

It seems to me that doing this either has to be restricted to enums with an “obvious” choice for unwrapping, like Optional, or rely on a sort of forward-looking type inference that Swift doesn’t currently use to deduce the unwrapped type based on how the value is used later (and I’m not sure that works in all cases, e.g. what if T == U for the TypeName example).

It succeeds on any one-item case and fails on any non-item case.

I think he meant this:

enum TypeName<T, U> { case anycase(T), anothercase(U) }

func foo<T, U>(instance: TypeName<T, U>) {
  guard unwrap instance else { ... }
}

What type does instance have?

···

On Oct 28, 2016, at 4:45 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 28, 2016, at 5:00 PM, Huon Wilson <huon@apple.com <mailto:huon@apple.com>> wrote:

On Oct 28, 2016, at 15:34, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-- E

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

I think I obscured my point: `guard unwrap`ing two values of the same type should result in two values that also have identical types, because the type of the binding can only be determined from the type of the thing being unwrapped.

In particular, I was thinking that you’re proposing that the first example becomes:

guard case .anycase(let first) = first { ... }

(Which will fail if first is anothercase, of course.)

While the second example becomes:

guard case .anothercase(let second) = second { ... }

(Which will similarly fail if second is anycase.)

Somehow the compiler needs to have a rule that chooses to use anycase for the first one and anothercase for the second. If it doesn’t do this, the shadowed variables can’t be given types T and U. Unfortunately, I don’t see any cues that the compiler can use to make the decision about when to use each version, and so I don’t think such a rule can exist in Swift.

All that said, based on your clarification, it sounds like you might actually be actually envisioning a different desugaring. Consider the following:

enum Enum { case a(Int), b(String), c }
let x: Enum = returnsEnum();
guard unwrap x else { ... }

Maybe it could be equivalent to the following (using x_shadow instead of the new x for clarity):

let x_shadow: /* ??? */

switch x {
case let .a(t): x_shadow = t
case let .b(u): x_shadow = u
default: /* else clause */
}

However, this also doesn’t work: what type fills in ???. Any and things like it are the only choice, but erasing the type seems somewhat backwards for an unwrapping feature.

Huon

···

On Oct 28, 2016, at 16:45, Erica Sadun <erica@ericasadun.com> wrote:

On Oct 28, 2016, at 5:00 PM, Huon Wilson <huon@apple.com <mailto:huon@apple.com>> wrote:

On Oct 28, 2016, at 15:34, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
<unwrap.md · GitHub Design

unwrap can be used with any one-value enumeration. The unwrapped value is bound to the same symbol as the associated type.

enum TypeName<T, U> { case anycase(T), anothercase(U) }

// First and second are type `TypeName`
let first = TypeName.anyCase(value1)
let second = TypeName. anothercase(value2)

guard unwrap first else { ... }
// first is now shadowed as type T

guard unwrap second else { ... }
// second is now shadowed as type U
<unwrap.md · GitHub;

How does the compiler decide whether to succeed on anycase or succeed on anothercase respectively? In general, the compiler only statically knows that first & second are of type TypeName, not anything about which case (they could be passed in as function parameters, or returned by an opaque function e.g. `let x = OtherLibrary.returnsTypeName(); guard unwrap x else { … }`), and thus the variant to unwrap has to be chosen based only on that piece of information.

It seems to me that doing this either has to be restricted to enums with an “obvious” choice for unwrapping, like Optional, or rely on a sort of forward-looking type inference that Swift doesn’t currently use to deduce the unwrapped type based on how the value is used later (and I’m not sure that works in all cases, e.g. what if T == U for the TypeName example).

It succeeds on any one-item case and fails on any non-item case.

-- E

<unwrap.md · GitHub Design

unwrap can be used with any one-value enumeration. The unwrapped value is bound to the same symbol as the associated type.

enum TypeName<T, U> { case anycase(T), anothercase(U) }

// First and second are type `TypeName`
let first = TypeName.anyCase(value1)
let second = TypeName. anothercase(value2)

guard unwrap first else { ... }
// first is now shadowed as type T

guard unwrap second else { ... }
// second is now shadowed as type U
<unwrap.md · GitHub;

How does the compiler decide whether to succeed on anycase or succeed on anothercase respectively? In general, the compiler only statically knows that first & second are of type TypeName, not anything about which case (they could be passed in as function parameters, or returned by an opaque function e.g. `let x = OtherLibrary.returnsTypeName(); guard unwrap x else { … }`), and thus the variant to unwrap has to be chosen based only on that piece of information.

It seems to me that doing this either has to be restricted to enums with an “obvious” choice for unwrapping, like Optional, or rely on a sort of forward-looking type inference that Swift doesn’t currently use to deduce the unwrapped type based on how the value is used later (and I’m not sure that works in all cases, e.g. what if T == U for the TypeName example).

It succeeds on any one-item case and fails on any non-item case.

I think he meant this:

enum TypeName<T, U> { case anycase(T), anothercase(U) }

func foo<T, U>(instance: TypeName<T, U>) {
  guard unwrap instance else { ... }
}

What type does instance have?

Fair enough. How about: An unwrappable enumeration must have at most one generic type so the compiler can guarantee at compile time that the type is unambiguous if the unwrapping succeeds

-- E

···

On Oct 28, 2016, at 5:55 PM, Kevin Nattinger <swift@nattinger.net> wrote:

On Oct 28, 2016, at 4:45 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Oct 28, 2016, at 5:00 PM, Huon Wilson <huon@apple.com <mailto:huon@apple.com>> wrote:

On Oct 28, 2016, at 15:34, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Because there's an action taking place in addition to guarding

-- E

···

On Oct 31, 2016, at 12:30 PM, Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:

Why have the “unwrap” keyword at all? Isn’t “guard” the keyword?

guard blah else {
}

-Kenny

On Oct 28, 2016, at 3:34 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 26, 2016, at 11:39 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 26, 2016, at 10:23 AM, Joshua Alvarado <alvaradojoshua0@gmail.com> wrote:

In your example the keyword only makes sense if you are shadowing the optional variable. How would unwrap work with a different name?

It wouldn’t: “unwrap” would never include an equal sign. If you want to do that, use a standard "if let”.

-Chris

So I can stop thinking about this. Gist is here: unwrap.md · GitHub

-- E

Introducing unwrap

  • Proposal: TBD
  • Author: Erica Sadun, Chris Lattner, David Goodine
  • Status: TBD
  • Review manager: TBD
Introduction

This proposal introduces unwrap, simplifying common shadowing and allowing a unified syntax for one-item associated values such as Result types.

Swift-evolution thread: guard let x = x

Motivation

Swift lacks a unified, safe way to bind an optional or single-value enumeration to a shadowed varaiable that is guaranteed to be the same name. Introducing unwrap ensures the conditionally bound item does not accidentally shadow any other item.

Compare:

guard let foobar = foobar else { …
}

guard unwrap foobar else { … }
Using unwrap eliminates repetition ("foobar = foobar" fails DRY principles) and retains clarity. The keyword is common, simple to understand, and easy to search for if Swift users are unfamiliar with it.

This syntax simplifies one-item associated value enumerations by offering a common syntax. Compare:

enum Result<T> { case success(T), error(Error
) }

guard case let .success(value) = result else { ...
}

guard unwrap result else { ... }
In the latter case result is bound to the wrapped value. Again, it is simpler and clearer, even with non-Optional types.

Detailed Design

unwrap can be used with any one-value enumeration. The unwrapped value is bound to the same symbol as the associated type.

enum TypeName<T, U> { case anycase(T), anothercase(U) }

// First and second are type `TypeName`
let first = TypeName.anyCase(value1)
let second = TypeName. anothercase(value2)

guard unwrap first else { ... }
// first is now shadowed as type T

guard unwrap second else { ... }
// second is now shadowed as type U

Impact on Existing Code

This change is additive and has no impact on existing code other than intentional refactoring.

Timeline

This proposal is additive and not suited for consideration until Swift 4 phase 2

Alternatives Considered

  • Using a bind keyword. Past discussions were held in the first week of February 2016.
  • Fixing pattern matching grammar
  • Not using this approach

_______________________________________________
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

A big YES to this!

As long as "the scope guarded by the condition” means everything after the guard statement, and not everything inside an if statement.

-Kenny

···

On Oct 31, 2016, at 6:37 PM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

Sorry for piling onto the bikeshed. We do already have a notation for testing that an Optional isn't nil, `x != nil`. We could theoretically bless `<decl ref> != nil` as a statement condition to also unwrap the referenced declaration in the scope guarded by the condition. (`<decl ref> is T` could similarly rebind a declaration as the cast type.)

-Joe

On Oct 28, 2016, at 3:34 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 26, 2016, at 11:39 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 26, 2016, at 10:23 AM, Joshua Alvarado <alvaradojoshua0@gmail.com> wrote:

In your example the keyword only makes sense if you are shadowing the optional variable. How would unwrap work with a different name?

It wouldn’t: “unwrap” would never include an equal sign. If you want to do that, use a standard "if let”.

-Chris

So I can stop thinking about this. Gist is here: unwrap.md · GitHub

-- E

Introducing unwrap

  • Proposal: TBD
  • Author: Erica Sadun, Chris Lattner, David Goodine
  • Status: TBD
  • Review manager: TBD
Introduction

This proposal introduces unwrap, simplifying common shadowing and allowing a unified syntax for one-item associated values such as Result types.

Swift-evolution thread: guard let x = x

Motivation

Swift lacks a unified, safe way to bind an optional or single-value enumeration to a shadowed varaiable that is guaranteed to be the same name. Introducing unwrap ensures the conditionally bound item does not accidentally shadow any other item.

Compare:

guard let foobar = foobar else { …
}

guard unwrap foobar else { … }
Using unwrap eliminates repetition ("foobar = foobar" fails DRY principles) and retains clarity. The keyword is common, simple to understand, and easy to search for if Swift users are unfamiliar with it.

This syntax simplifies one-item associated value enumerations by offering a common syntax. Compare:

enum Result<T> { case success(T), error(Error
) }

guard case let .success(value) = result else { ...
}

guard unwrap result else { ... }
In the latter case result is bound to the wrapped value. Again, it is simpler and clearer, even with non-Optional types.

Detailed Design

unwrap can be used with any one-value enumeration. The unwrapped value is bound to the same symbol as the associated type.

enum TypeName<T, U> { case anycase(T), anothercase(U) }

// First and second are type `TypeName`
let first = TypeName.anyCase(value1)
let second = TypeName. anothercase(value2)

guard unwrap first else { ... }
// first is now shadowed as type T

guard unwrap second else { ... }
// second is now shadowed as type U

Impact on Existing Code

This change is additive and has no impact on existing code other than intentional refactoring.

Timeline

This proposal is additive and not suited for consideration until Swift 4 phase 2

Alternatives Considered

  • Using a bind keyword. Past discussions were held in the first week of February 2016.
  • Fixing pattern matching grammar
  • Not using this approach

_______________________________________________
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

Sorry for piling onto the bikeshed. We do already have a notation for
testing that an Optional isn't nil, `x != nil`. We could theoretically
bless `<decl ref> != nil` as a statement condition to also unwrap the
referenced declaration in the scope guarded by the condition. (`<decl ref>
is T` could similarly rebind a declaration as the cast type.)

I think we'd have some weirdness. For instance:

guard x != nil || x == y else { break }
// oops, now x isn't unwrapped anymore because I added a condition

Also, it'd be unexpected for it to be blessed for guard but not if:

if x != nil {
  // is x unwrapped here?
  // if so, this would be source-breaking...
  // if not, it would be surprisingly inconsistent
}
···

On Mon, Oct 31, 2016 at 8:37 PM, Joe Groff via swift-evolution < swift-evolution@swift.org> wrote:

-Joe

> On Oct 28, 2016, at 3:34 PM, Erica Sadun via swift-evolution < > swift-evolution@swift.org> wrote:
>
>
>> On Oct 26, 2016, at 11:39 AM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>>
>>> On Oct 26, 2016, at 10:23 AM, Joshua Alvarado < > alvaradojoshua0@gmail.com> wrote:
>>>
>>> In your example the keyword only makes sense if you are shadowing the
optional variable. How would unwrap work with a different name?
>>
>> It wouldn’t: “unwrap” would never include an equal sign. If you want
to do that, use a standard "if let”.
>>
>> -Chris
>
> So I can stop thinking about this. Gist is here:
unwrap.md · GitHub
>
> -- E
>
>
> Introducing unwrap
>
> • Proposal: TBD
> • Author: Erica Sadun, Chris Lattner, David Goodine
> • Status: TBD
> • Review manager: TBD
> Introduction
>
> This proposal introduces unwrap, simplifying common shadowing and
allowing a unified syntax for one-item associated values such as Result
types.
>
> Swift-evolution thread: guard let x = x
>
> Motivation
>
> Swift lacks a unified, safe way to bind an optional or single-value
enumeration to a shadowed varaiable that is guaranteed to be the same name.
Introducing unwrap ensures the conditionally bound item does not
accidentally shadow any other item.
>
> Compare:
>
> guard let foobar = foobar else { …
> }
>
> guard unwrap foobar else { … }
> Using unwrap eliminates repetition ("foobar = foobar" fails DRY
principles) and retains clarity. The keyword is common, simple to
understand, and easy to search for if Swift users are unfamiliar with it.
>
> This syntax simplifies one-item associated value enumerations by
offering a common syntax. Compare:
>
> enum Result<T> { case success(T), error(Error
> ) }
>
>
> guard case let .success(value) = result else { ...
> }
>
> guard unwrap result else { ... }
> In the latter case result is bound to the wrapped value. Again, it is
simpler and clearer, even with non-Optional types.
>
> Detailed Design
>
> unwrap can be used with any one-value enumeration. The unwrapped value
is bound to the same symbol as the associated type.
>
> enum TypeName<T, U> { case anycase(T), anothercase(U) }
>
> // First and second are type `TypeName`
> let first = TypeName.anyCase(value1)
> let second = TypeName. anothercase(value2)
>
> guard unwrap first else { ... }
> // first is now shadowed as type T
>
> guard unwrap second else { ... }
> // second is now shadowed as type U
>
> Impact on Existing Code
>
> This change is additive and has no impact on existing code other than
intentional refactoring.
>
> Timeline
>
> This proposal is additive and not suited for consideration until Swift 4
phase 2
>
> Alternatives Considered
>
> • Using a bind keyword. Past discussions were held in the first
week of February 2016.
> • Fixing pattern matching grammar
> • Not using this approach
>
> _______________________________________________
> 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

Was about the say the same thing; this is basically the same idea as type narrowing, which is something I think that Swift still really needs, and can be used to solve this problem without the need for new syntax, enabling things like:

  if (a is Foo) { a.someMethodSpecificToFoo() }
  if (a != nil) { a.someMethodWithoutUnwrapping() }

While I've often suggested keywords to solve other problems, I'm not sure if we really need one to solve this use-case!

···

On 1 Nov 2016, at 01:37, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

Sorry for piling onto the bikeshed. We do already have a notation for testing that an Optional isn't nil, `x != nil`. We could theoretically bless `<decl ref> != nil` as a statement condition to also unwrap the referenced declaration in the scope guarded by the condition. (`<decl ref> is T` could similarly rebind a declaration as the cast type.)

-Joe