Obsoleting `if let`

This is a continuation of and alternative proposal to "The bind thread", which seems to have petered out without consensus.

Currently there are three forms of `if` statement (and `guard` and `while`, but for simplicity I'll just say `if` throughout this discussion):

  if booleanCondition
  if let name = optionalCondition
  if case pattern = expression

The boolean condition form is fine, but there are flaws in the other two. `if let` is unprincipled and doesn't really say what it does; `if case` is bulky and rarely used.*

One very interesting thing about `if case`, too, is that it can actually do optional unwrapping:

  if case let name? = optionalCondition

This avoids the problems with `if let`—it's principled (it comes from a larger language feature) and it explicitly says it's handling optionality—but it still runs up against `if case`'s rarity and wordiness.

So what I suggest is that we drop the `if let` form entirely and then drop the `case` keyword from `if case`. Pattern-matching conditions can still be distinguished from boolean conditions because boolean conditions can't contain an `=` operator. This, there would now only be two forms of if:

  if booleanCondition
  if pattern = expression

And the current `if let` is handled elegantly and clearly by existing pattern-matching shorthand, with only one additional character needed:

  if let name? = optionalCondition

I see two complications with this.

The first is that, naively, `if let foo = bar` would still be valid, but would have different and vacuous behavior, since the pattern cannot fail to match. The compiler should probably emit an error or at least a warning when this happens.

The second is our other weird use of the `case` keyword, `for case`, which is now an orphan in the language. I see several ways this could be handled:

1. Drop the `for case` functionality entirely; if you want that behavior, use a pattern-matching `if`.
2. Replace the loop variable slot in the `for` statement with a pattern. This would force you to put `let` on all simple `for` statements.
3. Try to automatically distinguish between simple variables/tuples and patterns in this slot. What could possibly go wrong?
4. Require an equals sign before the `in`, like `for let foo? = in optionalFoos`. Looks a little gross, but it's unambiguous.
5. Replace `for case` with `for if`, like `for if let foo? in optionalFoos`. This helps flag the unusual conditional behavior of this form of `for`.
6. Just keep `for case` and don't worry about the fact that it's not parallel to the other statements anymore.

Thoughts on any of this?

* `if case` also has the problem that the `=` isn't appropriate unless you happen to bind some of the data matched by the pattern, but I don't know how to address that. A prior version of this proposal suggested saying `:=` instead of `=`, with the idea that `:=` could become a general pattern-matching operator, but the people I talked over this post with hated that.

···

--
Brent Royal-Gordon
Architechies

Data point (which Chris brought up already, I think?): We tried this* and got a lot of negative feedback. Optionals are unwrapped too often for people to be comfortable writing "if let name? = optionalCondition".

It may be more uniform and even more pedantically correct, but our users hated it.

Jordan

* The actual thing we tried only allowed patterns that began with 'let', but that's close enough.

···

On Feb 3, 2016, at 15:36, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

This is a continuation of and alternative proposal to "The bind thread", which seems to have petered out without consensus.

Currently there are three forms of `if` statement (and `guard` and `while`, but for simplicity I'll just say `if` throughout this discussion):

  if booleanCondition
  if let name = optionalCondition
  if case pattern = expression

The boolean condition form is fine, but there are flaws in the other two. `if let` is unprincipled and doesn't really say what it does; `if case` is bulky and rarely used.*

One very interesting thing about `if case`, too, is that it can actually do optional unwrapping:

  if case let name? = optionalCondition

This avoids the problems with `if let`—it's principled (it comes from a larger language feature) and it explicitly says it's handling optionality—but it still runs up against `if case`'s rarity and wordiness.

So what I suggest is that we drop the `if let` form entirely and then drop the `case` keyword from `if case`. Pattern-matching conditions can still be distinguished from boolean conditions because boolean conditions can't contain an `=` operator. This, there would now only be two forms of if:

  if booleanCondition
  if pattern = expression

And the current `if let` is handled elegantly and clearly by existing pattern-matching shorthand, with only one additional character needed:

  if let name? = optionalCondition

I see two complications with this.

The first is that, naively, `if let foo = bar` would still be valid, but would have different and vacuous behavior, since the pattern cannot fail to match. The compiler should probably emit an error or at least a warning when this happens.

The second is our other weird use of the `case` keyword, `for case`, which is now an orphan in the language. I see several ways this could be handled:

1. Drop the `for case` functionality entirely; if you want that behavior, use a pattern-matching `if`.
2. Replace the loop variable slot in the `for` statement with a pattern. This would force you to put `let` on all simple `for` statements.
3. Try to automatically distinguish between simple variables/tuples and patterns in this slot. What could possibly go wrong?
4. Require an equals sign before the `in`, like `for let foo? = in optionalFoos`. Looks a little gross, but it's unambiguous.
5. Replace `for case` with `for if`, like `for if let foo? in optionalFoos`. This helps flag the unusual conditional behavior of this form of `for`.
6. Just keep `for case` and don't worry about the fact that it's not parallel to the other statements anymore.

Thoughts on any of this?

* `if case` also has the problem that the `=` isn't appropriate unless you happen to bind some of the data matched by the pattern, but I don't know how to address that. A prior version of this proposal suggested saying `:=` instead of `=`, with the idea that `:=` could become a general pattern-matching operator, but the people I talked over this post with hated that.

--
Brent Royal-Gordon
Architechies

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

1 Like

This was in fact our original design for the pattern-matching-in-conditions feature. We went with the alternative 'if case' design for a couple of reasons:

- As you noted, for loops are weird. `for case` makes it clearer that filtering is happening, whereas something like 'for x as T in sequence' is more ambiguous.
- The way 'if let x = y' ends up a no-op is a big pitfall
- Optional unwrapping is by far the most common use case for these conditions, and we got a huge amount of pushback from our users in Apple complaining about the extra syntax all over their code. 'if let' for better or worse has also become one of Swift's trademarks.

I like this unification as an ivory-tower language designer, but user experience had to win out.

-Joe

···

On Feb 3, 2016, at 3:36 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

This is a continuation of and alternative proposal to "The bind thread", which seems to have petered out without consensus.

Currently there are three forms of `if` statement (and `guard` and `while`, but for simplicity I'll just say `if` throughout this discussion):

  if booleanCondition
  if let name = optionalCondition
  if case pattern = expression

The boolean condition form is fine, but there are flaws in the other two. `if let` is unprincipled and doesn't really say what it does; `if case` is bulky and rarely used.*

One very interesting thing about `if case`, too, is that it can actually do optional unwrapping:

  if case let name? = optionalCondition

This avoids the problems with `if let`—it's principled (it comes from a larger language feature) and it explicitly says it's handling optionality—but it still runs up against `if case`'s rarity and wordiness.

So what I suggest is that we drop the `if let` form entirely and then drop the `case` keyword from `if case`. Pattern-matching conditions can still be distinguished from boolean conditions because boolean conditions can't contain an `=` operator. This, there would now only be two forms of if:

  if booleanCondition
  if pattern = expression

And the current `if let` is handled elegantly and clearly by existing pattern-matching shorthand, with only one additional character needed:

  if let name? = optionalCondition

Data point (which Chris brought up already, I think?): We tried this* and got a lot of negative feedback. Optionals are unwrapped too often for people to be comfortable writing "if let name? = optionalCondition”.

Yes, I even implemented this and it was in the compiler for awhile, then later ripped it back out. You can find the history in git. I would guess that this all happened in ~March 2015.

-Chris

···

On Feb 3, 2016, at 3:47 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

It may be more uniform and even more pedantically correct, but our users hated it.

Jordan

* The actual thing we tried only allowed patterns that began with 'let', but that's close enough.

On Feb 3, 2016, at 15:36, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This is a continuation of and alternative proposal to "The bind thread", which seems to have petered out without consensus.

Currently there are three forms of `if` statement (and `guard` and `while`, but for simplicity I'll just say `if` throughout this discussion):

  if booleanCondition
  if let name = optionalCondition
  if case pattern = expression

The boolean condition form is fine, but there are flaws in the other two. `if let` is unprincipled and doesn't really say what it does; `if case` is bulky and rarely used.*

One very interesting thing about `if case`, too, is that it can actually do optional unwrapping:

  if case let name? = optionalCondition

This avoids the problems with `if let`—it's principled (it comes from a larger language feature) and it explicitly says it's handling optionality—but it still runs up against `if case`'s rarity and wordiness.

So what I suggest is that we drop the `if let` form entirely and then drop the `case` keyword from `if case`. Pattern-matching conditions can still be distinguished from boolean conditions because boolean conditions can't contain an `=` operator. This, there would now only be two forms of if:

  if booleanCondition
  if pattern = expression

And the current `if let` is handled elegantly and clearly by existing pattern-matching shorthand, with only one additional character needed:

  if let name? = optionalCondition

I see two complications with this.

The first is that, naively, `if let foo = bar` would still be valid, but would have different and vacuous behavior, since the pattern cannot fail to match. The compiler should probably emit an error or at least a warning when this happens.

The second is our other weird use of the `case` keyword, `for case`, which is now an orphan in the language. I see several ways this could be handled:

1. Drop the `for case` functionality entirely; if you want that behavior, use a pattern-matching `if`.
2. Replace the loop variable slot in the `for` statement with a pattern. This would force you to put `let` on all simple `for` statements.
3. Try to automatically distinguish between simple variables/tuples and patterns in this slot. What could possibly go wrong?
4. Require an equals sign before the `in`, like `for let foo? = in optionalFoos`. Looks a little gross, but it's unambiguous.
5. Replace `for case` with `for if`, like `for if let foo? in optionalFoos`. This helps flag the unusual conditional behavior of this form of `for`.
6. Just keep `for case` and don't worry about the fact that it's not parallel to the other statements anymore.

Thoughts on any of this?

* `if case` also has the problem that the `=` isn't appropriate unless you happen to bind some of the data matched by the pattern, but I don't know how to address that. A prior version of this proposal suggested saying `:=` instead of `=`, with the idea that `:=` could become a general pattern-matching operator, but the people I talked over this post with hated that.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

I already suggested this in the bind thread but I guess it was either not interesting or people missed it, so here it goes again :)

What about changing the syntax of optional binding such that the optional unwrapping becomes explicit? I.e. instead of

  if let x = some_optional { }

one writes

  if let x = some_optional! { }

Essentially, the point of this suggestion is that the runtime error generated by unwrapping an empty Optional is instead treated as condition failure in a conditional statement. While there is some typing overhead over the current syntax, I see a number of potential benefits of this approach:

1. It is in line with the current semantics and syntax of optional unwrapping (does not introduce any new syntagm)
2. It makes the unwrapping operation explicit (thus addressing the basic criticism from the bind discussion)
3. It frees variable declaration of the contextual polisemy (i.e. let and var have the same semantics as nowhere else, there is no ‘unwrapping’ magic)
4. The change is minimal compare to what we have now and can be easily ported automatically

Potential issues:

1. One character typing overhead — but I dot think that should matter. I always had the impression that Swift favours clarity over compactness (which is a good thing IMO)
2. it allows syntactic ambiguity with optional chaining. E.g. if let x = a.b?.c! { } and if let x = a.b!.c would have the same meaning. Then again, this ambiguity already exits in the language to begin with.

— Taras

···

On 04 Feb 2016, at 01:25, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 3, 2016, at 3:47 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Data point (which Chris brought up already, I think?): We tried this* and got a lot of negative feedback. Optionals are unwrapped too often for people to be comfortable writing "if let name? = optionalCondition”.

Yes, I even implemented this and it was in the compiler for awhile, then later ripped it back out. You can find the history in git. I would guess that this all happened in ~March 2015.

-Chris

It may be more uniform and even more pedantically correct, but our users hated it.

Jordan

* The actual thing we tried only allowed patterns that began with 'let', but that's close enough.

On Feb 3, 2016, at 15:36, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This is a continuation of and alternative proposal to "The bind thread", which seems to have petered out without consensus.

Currently there are three forms of `if` statement (and `guard` and `while`, but for simplicity I'll just say `if` throughout this discussion):

  if booleanCondition
  if let name = optionalCondition
  if case pattern = expression

The boolean condition form is fine, but there are flaws in the other two. `if let` is unprincipled and doesn't really say what it does; `if case` is bulky and rarely used.*

One very interesting thing about `if case`, too, is that it can actually do optional unwrapping:

  if case let name? = optionalCondition

This avoids the problems with `if let`—it's principled (it comes from a larger language feature) and it explicitly says it's handling optionality—but it still runs up against `if case`'s rarity and wordiness.

So what I suggest is that we drop the `if let` form entirely and then drop the `case` keyword from `if case`. Pattern-matching conditions can still be distinguished from boolean conditions because boolean conditions can't contain an `=` operator. This, there would now only be two forms of if:

  if booleanCondition
  if pattern = expression

And the current `if let` is handled elegantly and clearly by existing pattern-matching shorthand, with only one additional character needed:

  if let name? = optionalCondition

I see two complications with this.

The first is that, naively, `if let foo = bar` would still be valid, but would have different and vacuous behavior, since the pattern cannot fail to match. The compiler should probably emit an error or at least a warning when this happens.

The second is our other weird use of the `case` keyword, `for case`, which is now an orphan in the language. I see several ways this could be handled:

1. Drop the `for case` functionality entirely; if you want that behavior, use a pattern-matching `if`.
2. Replace the loop variable slot in the `for` statement with a pattern. This would force you to put `let` on all simple `for` statements.
3. Try to automatically distinguish between simple variables/tuples and patterns in this slot. What could possibly go wrong?
4. Require an equals sign before the `in`, like `for let foo? = in optionalFoos`. Looks a little gross, but it's unambiguous.
5. Replace `for case` with `for if`, like `for if let foo? in optionalFoos`. This helps flag the unusual conditional behavior of this form of `for`.
6. Just keep `for case` and don't worry about the fact that it's not parallel to the other statements anymore.

Thoughts on any of this?

* `if case` also has the problem that the `=` isn't appropriate unless you happen to bind some of the data matched by the pattern, but I don't know how to address that. A prior version of this proposal suggested saying `:=` instead of `=`, with the idea that `:=` could become a general pattern-matching operator, but the people I talked over this post with hated that.

--
Brent Royal-Gordon
Architechies

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

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

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

FWIW, I don't see any problems with the current "if let x = ... " syntax or
behavior. I view it as a mainstream language finally implementing
anaphoric-if (as described in Paul Graham's _On Lisp_), and the unwrapping
seems like a natural consequence of the semantics, because what else
*could* it do? The if-statement needs to test on something; it seems
natural to me that the if tests for optional == nil, and then the let binds
the payload of the optional if it matches.

I wouldn't rule out there being something better, but I'm -1 on all the
proposals I've seen so far to change it.

···

On Wed, Feb 3, 2016 at 7:49 PM, Taras Zakharko via swift-evolution < swift-evolution@swift.org> wrote:

I already suggested this in the bind thread but I guess it was either not
interesting or people missed it, so here it goes again :)

What about changing the syntax of optional binding such that the optional
unwrapping becomes explicit? I.e. instead of

  if let x = some_optional { }

one writes

  if let x = some_optional! { }

Essentially, the point of this suggestion is that the runtime error
generated by unwrapping an empty Optional is instead treated as condition
failure in a conditional statement. While there is some typing overhead
over the current syntax, I see a number of potential benefits of this
approach:

1. It is in line with the current semantics and syntax of optional
unwrapping (does not introduce any new syntagm)
2. It makes the unwrapping operation explicit (thus addressing the basic
criticism from the bind discussion)
3. It frees variable declaration of the contextual polisemy (i.e. let and
var have the same semantics as nowhere else, there is no ‘unwrapping’ magic)
4. The change is minimal compare to what we have now and can be easily
ported automatically

Potential issues:

1. One character typing overhead — but I dot think that should matter. I
always had the impression that Swift favours clarity over compactness
(which is a good thing IMO)
2. it allows syntactic ambiguity with optional chaining. E.g. if let x =
a.b?.c! { } and if let x = a.b!.c would have the same meaning. Then again,
this ambiguity already exits in the language to begin with.

— Taras

On 04 Feb 2016, at 01:25, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:

On Feb 3, 2016, at 3:47 PM, Jordan Rose via swift-evolution < > swift-evolution@swift.org> wrote:

Data point (which Chris brought up already, I think?): We tried this* and
got a *lot* of negative feedback. Optionals are unwrapped too often for
people to be comfortable writing "if let name? = optionalCondition”.

Yes, I even implemented this and it was in the compiler for awhile, then
later ripped it back out. You can find the history in git. I would guess
that this all happened in ~March 2015.

-Chris

It may be more uniform and even more pedantically correct, but our users
hated it.

Jordan

* The actual thing we tried only allowed patterns that began with 'let',
but that's close enough.

On Feb 3, 2016, at 15:36, Brent Royal-Gordon via swift-evolution < > swift-evolution@swift.org> wrote:

This is a continuation of and alternative proposal to "The bind thread",
which seems to have petered out without consensus.

Currently there are three forms of `if` statement (and `guard` and
`while`, but for simplicity I'll just say `if` throughout this discussion):

if booleanCondition
if let name = optionalCondition
if case pattern = expression

The boolean condition form is fine, but there are flaws in the other two.
`if let` is unprincipled and doesn't really say what it does; `if case` is
bulky and rarely used.*

One very interesting thing about `if case`, too, is that it can actually
do optional unwrapping:

if case let name? = optionalCondition

This avoids the problems with `if let`—it's principled (it comes from a
larger language feature) and it explicitly says it's handling
optionality—but it still runs up against `if case`'s rarity and wordiness.

So what I suggest is that we drop the `if let` form entirely and then drop
the `case` keyword from `if case`. Pattern-matching conditions can still be
distinguished from boolean conditions because boolean conditions can't
contain an `=` operator. This, there would now only be two forms of if:

if booleanCondition
if pattern = expression

And the current `if let` is handled elegantly and clearly by existing
pattern-matching shorthand, with only one additional character needed:

if let name? = optionalCondition

I see two complications with this.

The first is that, naively, `if let foo = bar` would still be valid, but
would have different and vacuous behavior, since the pattern cannot fail to
match. The compiler should probably emit an error or at least a warning
when this happens.

The second is our other weird use of the `case` keyword, `for case`, which
is now an orphan in the language. I see several ways this could be handled:

1. Drop the `for case` functionality entirely; if you want that behavior,
use a pattern-matching `if`.
2. Replace the loop variable slot in the `for` statement with a pattern.
This would force you to put `let` on all simple `for` statements.
3. Try to automatically distinguish between simple variables/tuples and
patterns in this slot. What could possibly go wrong?
4. Require an equals sign before the `in`, like `for let foo? = in
optionalFoos`. Looks a little gross, but it's unambiguous.
5. Replace `for case` with `for if`, like `for if let foo? in
optionalFoos`. This helps flag the unusual conditional behavior of this
form of `for`.
6. Just keep `for case` and don't worry about the fact that it's not
parallel to the other statements anymore.

Thoughts on any of this?

* `if case` also has the problem that the `=` isn't appropriate unless you
happen to bind some of the data matched by the pattern, but I don't know
how to address that. A prior version of this proposal suggested saying `:=`
instead of `=`, with the idea that `:=` could become a general
pattern-matching operator, but the people I talked over this post with
hated that.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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

_______________________________________________
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

I agree with Jonathan; furthermore, Swift already puts aside 'principled behavior' in favor of pragmatically giving Optional special treatment in quite a few other ways, none of which have bothered people as much as 'if let'.

My question is, what's the advantage any such change is going to provide in exchange for the inevitable costs of broken code and programmer friction? Is it going to prevent or reduce a commonly-made mistake, or add expressivity to the language? Is it going to allow the compiler to generate better code? Is it necessary to lay the foundation for future features? In my opinion, a slight increase in orthogonality is not really a good enough justification.

Austin

···

On Feb 3, 2016, at 8:03 PM, Jonathan Tang via swift-evolution <swift-evolution@swift.org> wrote:

FWIW, I don't see any problems with the current "if let x = ... " syntax or behavior. I view it as a mainstream language finally implementing anaphoric-if (as described in Paul Graham's _On Lisp_), and the unwrapping seems like a natural consequence of the semantics, because what else *could* it do? The if-statement needs to test on something; it seems natural to me that the if tests for optional == nil, and then the let binds the payload of the optional if it matches.

I wouldn't rule out there being something better, but I'm -1 on all the proposals I've seen so far to change it.

On Wed, Feb 3, 2016 at 7:49 PM, Taras Zakharko via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I already suggested this in the bind thread but I guess it was either not interesting or people missed it, so here it goes again :)

What about changing the syntax of optional binding such that the optional unwrapping becomes explicit? I.e. instead of

  if let x = some_optional { }

one writes

  if let x = some_optional! { }

Essentially, the point of this suggestion is that the runtime error generated by unwrapping an empty Optional is instead treated as condition failure in a conditional statement. While there is some typing overhead over the current syntax, I see a number of potential benefits of this approach:

1. It is in line with the current semantics and syntax of optional unwrapping (does not introduce any new syntagm)
2. It makes the unwrapping operation explicit (thus addressing the basic criticism from the bind discussion)
3. It frees variable declaration of the contextual polisemy (i.e. let and var have the same semantics as nowhere else, there is no ‘unwrapping’ magic)
4. The change is minimal compare to what we have now and can be easily ported automatically

Potential issues:

1. One character typing overhead — but I dot think that should matter. I always had the impression that Swift favours clarity over compactness (which is a good thing IMO)
2. it allows syntactic ambiguity with optional chaining. E.g. if let x = a.b?.c! { } and if let x = a.b!.c would have the same meaning. Then again, this ambiguity already exits in the language to begin with.

— Taras

On 04 Feb 2016, at 01:25, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Feb 3, 2016, at 3:47 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Data point (which Chris brought up already, I think?): We tried this* and got a lot of negative feedback. Optionals are unwrapped too often for people to be comfortable writing "if let name? = optionalCondition”.

Yes, I even implemented this and it was in the compiler for awhile, then later ripped it back out. You can find the history in git. I would guess that this all happened in ~March 2015.

-Chris

It may be more uniform and even more pedantically correct, but our users hated it.

Jordan

* The actual thing we tried only allowed patterns that began with 'let', but that's close enough.

On Feb 3, 2016, at 15:36, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This is a continuation of and alternative proposal to "The bind thread", which seems to have petered out without consensus.

Currently there are three forms of `if` statement (and `guard` and `while`, but for simplicity I'll just say `if` throughout this discussion):

  if booleanCondition
  if let name = optionalCondition
  if case pattern = expression

The boolean condition form is fine, but there are flaws in the other two. `if let` is unprincipled and doesn't really say what it does; `if case` is bulky and rarely used.*

One very interesting thing about `if case`, too, is that it can actually do optional unwrapping:

  if case let name? = optionalCondition

This avoids the problems with `if let`—it's principled (it comes from a larger language feature) and it explicitly says it's handling optionality—but it still runs up against `if case`'s rarity and wordiness.

So what I suggest is that we drop the `if let` form entirely and then drop the `case` keyword from `if case`. Pattern-matching conditions can still be distinguished from boolean conditions because boolean conditions can't contain an `=` operator. This, there would now only be two forms of if:

  if booleanCondition
  if pattern = expression

And the current `if let` is handled elegantly and clearly by existing pattern-matching shorthand, with only one additional character needed:

  if let name? = optionalCondition

I see two complications with this.

The first is that, naively, `if let foo = bar` would still be valid, but would have different and vacuous behavior, since the pattern cannot fail to match. The compiler should probably emit an error or at least a warning when this happens.

The second is our other weird use of the `case` keyword, `for case`, which is now an orphan in the language. I see several ways this could be handled:

1. Drop the `for case` functionality entirely; if you want that behavior, use a pattern-matching `if`.
2. Replace the loop variable slot in the `for` statement with a pattern. This would force you to put `let` on all simple `for` statements.
3. Try to automatically distinguish between simple variables/tuples and patterns in this slot. What could possibly go wrong?
4. Require an equals sign before the `in`, like `for let foo? = in optionalFoos`. Looks a little gross, but it's unambiguous.
5. Replace `for case` with `for if`, like `for if let foo? in optionalFoos`. This helps flag the unusual conditional behavior of this form of `for`.
6. Just keep `for case` and don't worry about the fact that it's not parallel to the other statements anymore.

Thoughts on any of this?

* `if case` also has the problem that the `=` isn't appropriate unless you happen to bind some of the data matched by the pattern, but I don't know how to address that. A prior version of this proposal suggested saying `:=` instead of `=`, with the idea that `:=` could become a general pattern-matching operator, but the people I talked over this post with hated that.

--
Brent Royal-Gordon
Architechies

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

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

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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

Random factoid, but we briefly discussed how logical it would be if the ImplicitlyUnwrappedOptional sugar were T‽ instead of T!… :-)

-Chris

···

On Feb 3, 2016, at 8:02 PM, David Waite <david@alkaline-solutions.com> wrote:

-1 , as it changes the meaning of ‘!’ from ‘fault program on error’ to mere flow control.

I’m surprised nobody has beat me to suggesting the interrobang, though.

-1 , as it changes the meaning of ‘!’ from ‘fault program on error’ to mere flow control.

I’m surprised nobody has beat me to suggesting the interrobang, though.

-DW

···

On Feb 3, 2016, at 8:49 PM, Taras Zakharko via swift-evolution <swift-evolution@swift.org> wrote:

I already suggested this in the bind thread but I guess it was either not interesting or people missed it, so here it goes again :)

What about changing the syntax of optional binding such that the optional unwrapping becomes explicit? I.e. instead of

  if let x = some_optional { }

one writes

  if let x = some_optional! { }

Essentially, the point of this suggestion is that the runtime error generated by unwrapping an empty Optional is instead treated as condition failure in a conditional statement. While there is some typing overhead over the current syntax, I see a number of potential benefits of this approach:

1. It is in line with the current semantics and syntax of optional unwrapping (does not introduce any new syntagm)
2. It makes the unwrapping operation explicit (thus addressing the basic criticism from the bind discussion)
3. It frees variable declaration of the contextual polisemy (i.e. let and var have the same semantics as nowhere else, there is no ‘unwrapping’ magic)
4. The change is minimal compare to what we have now and can be easily ported automatically

Potential issues:

1. One character typing overhead — but I dot think that should matter. I always had the impression that Swift favours clarity over compactness (which is a good thing IMO)
2. it allows syntactic ambiguity with optional chaining. E.g. if let x = a.b?.c! { } and if let x = a.b!.c would have the same meaning. Then again, this ambiguity already exits in the language to begin with.

— Taras

On 04 Feb 2016, at 01:25, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Feb 3, 2016, at 3:47 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Data point (which Chris brought up already, I think?): We tried this* and got a lot of negative feedback. Optionals are unwrapped too often for people to be comfortable writing "if let name? = optionalCondition”.

Yes, I even implemented this and it was in the compiler for awhile, then later ripped it back out. You can find the history in git. I would guess that this all happened in ~March 2015.

-Chris

It may be more uniform and even more pedantically correct, but our users hated it.

Jordan

* The actual thing we tried only allowed patterns that began with 'let', but that's close enough.

On Feb 3, 2016, at 15:36, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This is a continuation of and alternative proposal to "The bind thread", which seems to have petered out without consensus.

Currently there are three forms of `if` statement (and `guard` and `while`, but for simplicity I'll just say `if` throughout this discussion):

  if booleanCondition
  if let name = optionalCondition
  if case pattern = expression

The boolean condition form is fine, but there are flaws in the other two. `if let` is unprincipled and doesn't really say what it does; `if case` is bulky and rarely used.*

One very interesting thing about `if case`, too, is that it can actually do optional unwrapping:

  if case let name? = optionalCondition

This avoids the problems with `if let`—it's principled (it comes from a larger language feature) and it explicitly says it's handling optionality—but it still runs up against `if case`'s rarity and wordiness.

So what I suggest is that we drop the `if let` form entirely and then drop the `case` keyword from `if case`. Pattern-matching conditions can still be distinguished from boolean conditions because boolean conditions can't contain an `=` operator. This, there would now only be two forms of if:

  if booleanCondition
  if pattern = expression

And the current `if let` is handled elegantly and clearly by existing pattern-matching shorthand, with only one additional character needed:

  if let name? = optionalCondition

I see two complications with this.

The first is that, naively, `if let foo = bar` would still be valid, but would have different and vacuous behavior, since the pattern cannot fail to match. The compiler should probably emit an error or at least a warning when this happens.

The second is our other weird use of the `case` keyword, `for case`, which is now an orphan in the language. I see several ways this could be handled:

1. Drop the `for case` functionality entirely; if you want that behavior, use a pattern-matching `if`.
2. Replace the loop variable slot in the `for` statement with a pattern. This would force you to put `let` on all simple `for` statements.
3. Try to automatically distinguish between simple variables/tuples and patterns in this slot. What could possibly go wrong?
4. Require an equals sign before the `in`, like `for let foo? = in optionalFoos`. Looks a little gross, but it's unambiguous.
5. Replace `for case` with `for if`, like `for if let foo? in optionalFoos`. This helps flag the unusual conditional behavior of this form of `for`.
6. Just keep `for case` and don't worry about the fact that it's not parallel to the other statements anymore.

Thoughts on any of this?

* `if case` also has the problem that the `=` isn't appropriate unless you happen to bind some of the data matched by the pattern, but I don't know how to address that. A prior version of this proposal suggested saying `:=` instead of `=`, with the idea that `:=` could become a general pattern-matching operator, but the people I talked over this post with hated that.

--
Brent Royal-Gordon
Architechies

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

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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

FWIW, I don't see any problems with the current "if let x = ... " syntax or behavior. I view it as a mainstream language finally implementing anaphoric-if (as described in Paul Graham's _On Lisp_), and the unwrapping seems like a natural consequence of the semantics, because what else *could* it do? The if-statement needs to test on something; it seems natural to me that the if tests for optional == nil, and then the let binds the payload of the optional if it matches.

To be honest, I agree. But the bind threads reveals that many consider the current if let less transparent, so it makes sense to discuss alternatives.

One problem I can see with privileging optionals binding in conditional statements however, is the inability to bind non-optionals. That would be quite useful sometimes. E.g. in conditionals:

  if let x = optional_value, y = some_fun_returning_non_optional() where x > y {}

forcing one to write something like this instead (or a nested if)

  myif: if x = optional_value {
    let y = some_fun_returning_non_optional()
    guard x > y else {break myif}
    ...
}

Same goes for guard, it would be nice to do something like

  guard let
      x = optional1,
      y = x.optional2,
      z = x.non_optional,
      w = z.optional3
  else {
    // failed to initialise
}

If I remember correctly, I encountered this problem when playing with Metal, where I wanted to initialise a bunch of relevant variables in one go, but had to break up my guards into a number of blocks. This breaks the program logic.

— Taras

···

On 04 Feb 2016, at 05:03, Jonathan Tang <jonathan.d.tang@gmail.com> wrote:

I wouldn't rule out there being something better, but I'm -1 on all the proposals I've seen so far to change it.

On Wed, Feb 3, 2016 at 7:49 PM, Taras Zakharko via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I already suggested this in the bind thread but I guess it was either not interesting or people missed it, so here it goes again :)

What about changing the syntax of optional binding such that the optional unwrapping becomes explicit? I.e. instead of

  if let x = some_optional { }

one writes

  if let x = some_optional! { }

Essentially, the point of this suggestion is that the runtime error generated by unwrapping an empty Optional is instead treated as condition failure in a conditional statement. While there is some typing overhead over the current syntax, I see a number of potential benefits of this approach:

1. It is in line with the current semantics and syntax of optional unwrapping (does not introduce any new syntagm)
2. It makes the unwrapping operation explicit (thus addressing the basic criticism from the bind discussion)
3. It frees variable declaration of the contextual polisemy (i.e. let and var have the same semantics as nowhere else, there is no ‘unwrapping’ magic)
4. The change is minimal compare to what we have now and can be easily ported automatically

Potential issues:

1. One character typing overhead — but I dot think that should matter. I always had the impression that Swift favours clarity over compactness (which is a good thing IMO)
2. it allows syntactic ambiguity with optional chaining. E.g. if let x = a.b?.c! { } and if let x = a.b!.c would have the same meaning. Then again, this ambiguity already exits in the language to begin with.

— Taras

On 04 Feb 2016, at 01:25, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Feb 3, 2016, at 3:47 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Data point (which Chris brought up already, I think?): We tried this* and got a lot of negative feedback. Optionals are unwrapped too often for people to be comfortable writing "if let name? = optionalCondition”.

Yes, I even implemented this and it was in the compiler for awhile, then later ripped it back out. You can find the history in git. I would guess that this all happened in ~March 2015.

-Chris

It may be more uniform and even more pedantically correct, but our users hated it.

Jordan

* The actual thing we tried only allowed patterns that began with 'let', but that's close enough.

On Feb 3, 2016, at 15:36, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This is a continuation of and alternative proposal to "The bind thread", which seems to have petered out without consensus.

Currently there are three forms of `if` statement (and `guard` and `while`, but for simplicity I'll just say `if` throughout this discussion):

  if booleanCondition
  if let name = optionalCondition
  if case pattern = expression

The boolean condition form is fine, but there are flaws in the other two. `if let` is unprincipled and doesn't really say what it does; `if case` is bulky and rarely used.*

One very interesting thing about `if case`, too, is that it can actually do optional unwrapping:

  if case let name? = optionalCondition

This avoids the problems with `if let`—it's principled (it comes from a larger language feature) and it explicitly says it's handling optionality—but it still runs up against `if case`'s rarity and wordiness.

So what I suggest is that we drop the `if let` form entirely and then drop the `case` keyword from `if case`. Pattern-matching conditions can still be distinguished from boolean conditions because boolean conditions can't contain an `=` operator. This, there would now only be two forms of if:

  if booleanCondition
  if pattern = expression

And the current `if let` is handled elegantly and clearly by existing pattern-matching shorthand, with only one additional character needed:

  if let name? = optionalCondition

I see two complications with this.

The first is that, naively, `if let foo = bar` would still be valid, but would have different and vacuous behavior, since the pattern cannot fail to match. The compiler should probably emit an error or at least a warning when this happens.

The second is our other weird use of the `case` keyword, `for case`, which is now an orphan in the language. I see several ways this could be handled:

1. Drop the `for case` functionality entirely; if you want that behavior, use a pattern-matching `if`.
2. Replace the loop variable slot in the `for` statement with a pattern. This would force you to put `let` on all simple `for` statements.
3. Try to automatically distinguish between simple variables/tuples and patterns in this slot. What could possibly go wrong?
4. Require an equals sign before the `in`, like `for let foo? = in optionalFoos`. Looks a little gross, but it's unambiguous.
5. Replace `for case` with `for if`, like `for if let foo? in optionalFoos`. This helps flag the unusual conditional behavior of this form of `for`.
6. Just keep `for case` and don't worry about the fact that it's not parallel to the other statements anymore.

Thoughts on any of this?

* `if case` also has the problem that the `=` isn't appropriate unless you happen to bind some of the data matched by the pattern, but I don't know how to address that. A prior version of this proposal suggested saying `:=` instead of `=`, with the idea that `:=` could become a general pattern-matching operator, but the people I talked over this post with hated that.

--
Brent Royal-Gordon
Architechies

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

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

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

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

I feel a proposal coming on...

···

On Wed, Feb 3, 2016 at 8:39 PM Chris Lattner via swift-evolution < swift-evolution@swift.org> wrote:

> On Feb 3, 2016, at 8:02 PM, David Waite <david@alkaline-solutions.com> > wrote:
>
> -1 , as it changes the meaning of ‘!’ from ‘fault program on error’ to
mere flow control.
>
> I’m surprised nobody has beat me to suggesting the interrobang, though.

Random factoid, but we briefly discussed how logical it would be if the
ImplicitlyUnwrappedOptional sugar were T‽ instead of T!… :-)

-Chris

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

The original proposal says

  if let name? = optionalCondition { }

This would unwrap it?

This seems like it should be mean the opposite. For example, lets remove the “if” from this and just do a let statement:

  let name? = “some value”

this looks to me like it would take the string and upgrade it to an optional. In fact, I was thinking this would could be a new proposal. A easier way of writing this:

  let name : String? = “some value”

What is nice is this is easier to read and I think it is a kind of natural way of creating an optional without having to repeat the type.. It would also work on non literals. Is there a reason this would not work?

- Paul

The original proposal says

  if let name? = optionalCondition { }

This would unwrap it?

This seems like it should be mean the opposite.

The reason it unwraps it is that the thing on the left is a pattern, kind of like the cases of a case statement:

  switch optionalCondition {
  case let name?:
    // optionalCondition was not nil; name here is non-optional
  case nil:
    // optionalCondition was nil
  }

Think of it as the left side specifying a template the right side must match, with `let name` capturing the value corresponding to that particular position in the template.

···

--
Brent Royal-Gordon
Architechies

Right. This makes sense to you, it makes sense to me, but it doesn’t make sense to most people using Swift. More specifically, you can get a *long* way in Swift without understanding the depth of how pattern matching works in Swift, but if/let is inescapable.

-Chris

···

On Feb 3, 2016, at 10:23 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

The original proposal says

  if let name? = optionalCondition { }

This would unwrap it?

This seems like it should be mean the opposite.

The reason it unwraps it is that the thing on the left is a pattern, kind of like the cases of a case statement:

1 Like

Which is why the “case" is there to help people make that association. It makes people think of pattern matching. I think that is an important distinction so I would say -1 to this proposal.

···

On Feb 3, 2016, at 10:28 PM, Chris Lattner <clattner@apple.com> wrote:

On Feb 3, 2016, at 10:23 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

The original proposal says

  if let name? = optionalCondition { }

This would unwrap it?

This seems like it should be mean the opposite.

The reason it unwraps it is that the thing on the left is a pattern, kind of like the cases of a case statement:

Right. This makes sense to you, it makes sense to me, but it doesn’t make sense to most people using Swift. More specifically, you can get a *long* way in Swift without understanding the depth of how pattern matching works in Swift, but if/let is inescapable.

-Chris

Right. This makes sense to you, it makes sense to me, but it doesn’t make sense to most people using Swift. More specifically, you can get a *long* way in Swift without understanding the depth of how pattern matching works in Swift, but if/let is inescapable.

I'm not continuing to push this approach—you guys obviously tested it and it didn't work out. I just figured I'd explain where it was coming from.

···

--
Brent Royal-Gordon
Architechies

An idea that I've been kicking around would be to to replace if-(let/var/case)-where, guard-(let/var/case)-where with:

when <pattern> where <condition> {}
guard when <pattern> where <condition> else {}
if <condition> {} else {}
guard <condition> else {}

This seems pretty similar to the original design that Chris mentioned and which was rejected, but without it living inside of the "if-case" construct - instead "when" exists as its own kind of statement so "if" and "guard" can revert to a more standard form without binding / pattern matching.

"When" statement's patterns would allow some new variations to try to solve the pain points:

let foo: String?
var bar: String? = "thing"

when let exists = foo where exists == "hi" {
  // "foo" is still optional, not shadowed, "exists" only valid in this scope
}

when foo where foo == "hi" {
  // "foo" is a shadowed "let" because "foo" was originally a "let"
}

when bar where bar == "thing" {
   // "bar" is modeled like an inout and is mutable here because "bar" was a "var"
  // so changes to "bar" here will be set back to the outer "bar" when the scope ends
}

when var exists = foo {
  // "exists" is mutable local copy and only exists in this scope
}

when var bar = bar {
  // "bar" is a mutable shadowed copy of the outer "bar" and only exists in this scope
}

when case .thing(associated: value) = someEnumProperty {
  print(value)
}

All of these patterns would also apply to the guard variants as well with the obvious changes to the scoping.

I hope this isn't similar to the bind thread discussions since I haven't had time to keep up with everything there, but thought I'd toss it out here since it seemed to be on topic-ish.

l8r
Sean

···

Sent from my iPad

On Feb 3, 2016, at 10:41 PM, Taras Zakharko via swift-evolution <swift-evolution@swift.org> wrote:

On 04 Feb 2016, at 05:03, Jonathan Tang <jonathan.d.tang@gmail.com> wrote:

FWIW, I don't see any problems with the current "if let x = ... " syntax or behavior. I view it as a mainstream language finally implementing anaphoric-if (as described in Paul Graham's _On Lisp_), and the unwrapping seems like a natural consequence of the semantics, because what else *could* it do? The if-statement needs to test on something; it seems natural to me that the if tests for optional == nil, and then the let binds the payload of the optional if it matches.

To be honest, I agree. But the bind threads reveals that many consider the current if let less transparent, so it makes sense to discuss alternatives.

One problem I can see with privileging optionals binding in conditional statements however, is the inability to bind non-optionals. That would be quite useful sometimes. E.g. in conditionals:

  if let x = optional_value, y = some_fun_returning_non_optional() where x > y {}

forcing one to write something like this instead (or a nested if)

  myif: if x = optional_value {
    let y = some_fun_returning_non_optional()
    guard x > y else {break myif}
    ...
}

Same goes for guard, it would be nice to do something like

  guard let
      x = optional1,
      y = x.optional2,
      z = x.non_optional,
      w = z.optional3
  else {
    // failed to initialise
}

If I remember correctly, I encountered this problem when playing with Metal, where I wanted to initialise a bunch of relevant variables in one go, but had to break up my guards into a number of blocks. This breaks the program logic.

— Taras

I wouldn't rule out there being something better, but I'm -1 on all the proposals I've seen so far to change it.

On Wed, Feb 3, 2016 at 7:49 PM, Taras Zakharko via swift-evolution <swift-evolution@swift.org> wrote:
I already suggested this in the bind thread but I guess it was either not interesting or people missed it, so here it goes again :)

What about changing the syntax of optional binding such that the optional unwrapping becomes explicit? I.e. instead of

  if let x = some_optional { }

one writes

  if let x = some_optional! { }

Essentially, the point of this suggestion is that the runtime error generated by unwrapping an empty Optional is instead treated as condition failure in a conditional statement. While there is some typing overhead over the current syntax, I see a number of potential benefits of this approach:

1. It is in line with the current semantics and syntax of optional unwrapping (does not introduce any new syntagm)
2. It makes the unwrapping operation explicit (thus addressing the basic criticism from the bind discussion)
3. It frees variable declaration of the contextual polisemy (i.e. let and var have the same semantics as nowhere else, there is no ‘unwrapping’ magic)
4. The change is minimal compare to what we have now and can be easily ported automatically

Potential issues:

1. One character typing overhead — but I dot think that should matter. I always had the impression that Swift favours clarity over compactness (which is a good thing IMO)
2. it allows syntactic ambiguity with optional chaining. E.g. if let x = a.b?.c! { } and if let x = a.b!.c would have the same meaning. Then again, this ambiguity already exits in the language to begin with.

— Taras

On 04 Feb 2016, at 01:25, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 3, 2016, at 3:47 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

Data point (which Chris brought up already, I think?): We tried this* and got a lot of negative feedback. Optionals are unwrapped too often for people to be comfortable writing "if let name? = optionalCondition”.

Yes, I even implemented this and it was in the compiler for awhile, then later ripped it back out. You can find the history in git. I would guess that this all happened in ~March 2015.

-Chris

It may be more uniform and even more pedantically correct, but our users hated it.

Jordan

* The actual thing we tried only allowed patterns that began with 'let', but that's close enough.

On Feb 3, 2016, at 15:36, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

This is a continuation of and alternative proposal to "The bind thread", which seems to have petered out without consensus.

Currently there are three forms of `if` statement (and `guard` and `while`, but for simplicity I'll just say `if` throughout this discussion):

  if booleanCondition
  if let name = optionalCondition
  if case pattern = expression

The boolean condition form is fine, but there are flaws in the other two. `if let` is unprincipled and doesn't really say what it does; `if case` is bulky and rarely used.*

One very interesting thing about `if case`, too, is that it can actually do optional unwrapping:

  if case let name? = optionalCondition

This avoids the problems with `if let`—it's principled (it comes from a larger language feature) and it explicitly says it's handling optionality—but it still runs up against `if case`'s rarity and wordiness.

So what I suggest is that we drop the `if let` form entirely and then drop the `case` keyword from `if case`. Pattern-matching conditions can still be distinguished from boolean conditions because boolean conditions can't contain an `=` operator. This, there would now only be two forms of if:

  if booleanCondition
  if pattern = expression

And the current `if let` is handled elegantly and clearly by existing pattern-matching shorthand, with only one additional character needed:

  if let name? = optionalCondition

I see two complications with this.

The first is that, naively, `if let foo = bar` would still be valid, but would have different and vacuous behavior, since the pattern cannot fail to match. The compiler should probably emit an error or at least a warning when this happens.

The second is our other weird use of the `case` keyword, `for case`, which is now an orphan in the language. I see several ways this could be handled:

1. Drop the `for case` functionality entirely; if you want that behavior, use a pattern-matching `if`.
2. Replace the loop variable slot in the `for` statement with a pattern. This would force you to put `let` on all simple `for` statements.
3. Try to automatically distinguish between simple variables/tuples and patterns in this slot. What could possibly go wrong?
4. Require an equals sign before the `in`, like `for let foo? = in optionalFoos`. Looks a little gross, but it's unambiguous.
5. Replace `for case` with `for if`, like `for if let foo? in optionalFoos`. This helps flag the unusual conditional behavior of this form of `for`.
6. Just keep `for case` and don't worry about the fact that it's not parallel to the other statements anymore.

Thoughts on any of this?

* `if case` also has the problem that the `=` isn't appropriate unless you happen to bind some of the data matched by the pattern, but I don't know how to address that. A prior version of this proposal suggested saying `:=` instead of `=`, with the idea that `:=` could become a general pattern-matching operator, but the people I talked over this post with hated that.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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

_______________________________________________
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

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