ternary operator ?: suggestion

Ostensibly, case may not be necessary if you could delimit each case on one line with something (perhaps a comma, or something else if that would not fit well within the grammar):

let thisColor = thatColor ? .Blue: .Red, .Green: .Blue, .Red: .Green,
default: .Yellow

···

On Sun, Dec 6, 2015, at 01:57 PM, Paul Ossenbruggen via swift-evolution wrote:

I like this too, seems more powerful. Also, would single line
expressions be allowed? If not would case be required for example:

let myFavoriteColor = yourFavoriteColor ? case .Blue: .Red case
.Green: .Blue case .Red: .Green default: .Yellow

On Dec 6, 2015, at 9:11 AM, Sean Heber via swift-evolution <swift- >> evolution@swift.org> wrote:

I really like this train of thought. +1

l8r Sean

On Dec 6, 2015, at 11:02 AM, Alex Lew via swift-evolution <swift- >> evolution@swift.org> wrote:

What if we left the if { ...} else { ... } syntax alone (as a
statement), and updated the ternary expression to be a more general
pattern matching expression (closer to "switch")? Something like

let x = condition ? true: "Hello" false: "Goodbye"

let x = optionalValue ? .Some(let unwrapped): "Hello,
\(unwrapped)" .None: "To Whom It May Concern"

let myFavoriteColor = yourFavoriteColor ? .Blue: .Red .Green:
.Blue .Red: .Green

let quadrant = (x, y) ? let (x, y) where x < 50 && y < 50: "top
left" let (x, y) where x < 50 && y > 50: "bottom left" let (x,
y) where x > 50 && y < 50: "top right" default: "bottom right"

The colon comes from the fact that this is sort of a light-weight
expression-based "switch" statement, where each branch can only
contain an expression, not a series of statements.

This is very similar to pattern matching expressions in languages
like Haskell, ML, and Coq.

On Sun, Dec 6, 2015 at 11:25 AM, Thorsten >>> Seitz<thorsten.seitz@web.de>wrote:

Am 06.12.2015 um 01:28 schrieb Alex Lew via swift-evolution <swift- >>>>> evolution@swift.org>:

I don't think you can just get rid of the if statement in favor of
an expression. You still want to be able to do this:

if (condition) { funcWithSideEffectsThatReturnsInt() } else {
funcWithSideEffectsThatReturnsString() }

but that's not a valid expression (what is its type?).

That would actually be no problem if Swift’s type system would have
union types (Ceylon has union and intersection types which are
quite awesome and enable lots of nice things quite naturally, see
http://ceylon-lang.org/documentation/1.2/tour/types/\).

In that case the type of such an expression would just be the union
of both types, which is writtenInt | Stringin Ceylon.

-Thorsten

_______________________________________________
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

Yes, I'm of two minds about adding *case*.

On the one hand, it is much more consistent with the rest of the
language. *case
*is used everywhere else in Swift that pattern matching is allowed. (if
case..., for case..., while case...) I think this is a strong argument that
it should be used in pattern matching expressions too.

On the other hand, what is the point of pattern matching expressions if not
to be brief? They don't enable you to do anything you couldn't do before
with a switch and assignment, right? So it seems like a priority should be
getting them to look nice and readable, which the comma syntax does. It
actually doesn't look too bad with both case and comma:

let thisColor = thatColor ? case .Blue: .Red, case .Green: .Blue, default:
.Yellow

And on the third hand, it still does save you a good amount of space even
if you're not all on one line. Compare

let thisColor: Color
switch thatColor {
    case .Blue:
        thisColor = .Red
    case .Green
        thisColor = .Blue
    default:
        thisColor = .Yellow
}

with

let thisColor = thatColor ?
    case .Blue: .Red
    case .Green: .Blue
    default: .Yellow

···

On Sun, Dec 6, 2015 at 2:19 PM, Kevin Lundberg via swift-evolution < swift-evolution@swift.org> wrote:

Ostensibly, case may not be necessary if you could delimit each case on
one line with something (perhaps a comma, or something else if that would
not fit well within the grammar):

let thisColor = thatColor ? .Blue: .Red, .Green: .Blue, .Red: .Green,
default: .Yellow

On Sun, Dec 6, 2015, at 01:57 PM, Paul Ossenbruggen via swift-evolution > wrote:

I like this too, seems more powerful. Also, would single line expressions
be allowed? If not would case be required for example:

let myFavoriteColor = yourFavoriteColor ?
    case .Blue: .Red
    case .Green: .Blue
    case .Red: .Green
    default: .Yellow

On Dec 6, 2015, at 9:11 AM, Sean Heber via swift-evolution < > swift-evolution@swift.org> wrote:

I really like this train of thought. +1

l8r
Sean

On Dec 6, 2015, at 11:02 AM, Alex Lew via swift-evolution < > swift-evolution@swift.org> wrote:

What if we left the if { ...} else { ... } syntax alone (as a statement),
and updated the ternary expression to be a more general pattern matching
expression (closer to "switch")? Something like

let x = condition ?
   true: "Hello"
   false: "Goodbye"

let x = optionalValue ?
   .Some(let unwrapped): "Hello, \(unwrapped)"
   .None: "To Whom It May Concern"

let myFavoriteColor = yourFavoriteColor ?
    .Blue: .Red
    .Green: .Blue
    .Red: .Green

let quadrant = (x, y) ?
    let (x, y) where x < 50 && y < 50: "top left"
    let (x, y) where x < 50 && y > 50: "bottom left"
    let (x, y) where x > 50 && y < 50: "top right"
    default: "bottom right"

The colon comes from the fact that this is sort of a light-weight
expression-based "switch" statement, where each branch can only contain an
expression, not a series of statements.

This is very similar to pattern matching expressions in languages like
Haskell, ML, and Coq.

On Sun, Dec 6, 2015 at 11:25 AM, Thorsten Seitz <thorsten.seitz@web.de> wrote:

Am 06.12.2015 um 01:28 schrieb Alex Lew via swift-evolution < > swift-evolution@swift.org>:

I don't think you can just get rid of the if statement in favor of an
expression. You still want to be able to do this:

if (condition) {
    funcWithSideEffectsThatReturnsInt()
} else {
    funcWithSideEffectsThatReturnsString()
}

but that's not a valid expression (what is its type?).

That would actually be no problem if Swift’s type system would have union
types (Ceylon has union and intersection types which are quite awesome and
enable lots of nice things quite naturally, see
http://ceylon-lang.org/documentation/1.2/tour/types/\).

In that case the type of such an expression would just be the union of
both types, which is written Int | String in Ceylon.

-Thorsten

_______________________________________________
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

Untracked with Trackbuster <Your contacts automatically up to date | evercontact;

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

Thanks for the feedback, Matthew. It's sensible to me to consider dropping
the ternary operator. I like it because the analogy "C's if is to Swift's
if as C's ternary operator is to Swift's ternary operator" is (sort of)
satisfied. But it is also confusing, both for the reasons you mention, and
because ? has other meanings in Swift:

// compiler error without space betw thatColor and ?
let thisColor = thatColor?
     case .Red: .Green
     default: .Blue

On the other hand, is it really worth it to have control flow expressions
if they don't let your code look nicer?

let thisColor = switch thatColor {
     case .Red:
          return .Green;
     default:
          return .Yellow;
}

really isn't much nicer than

let thisColor: Color
switch thatColor {
     case .Red:
          thisColor = .Green
     default:
          thisColor = .Yellow
}

Maybe we could do a compromise, something like

let thisColor = switch thatColor
     case .Red: .Green // must be an expression
     default: .Yellow // must be an expression

Or we could introduce a new keyword? Like *match*:

let thisColor = match thatColor
      case .Red: .Green // must be an expression
      default: .Yellow // must be an expression

I sort of like the new-keyword approach, because even though this is
similar to a switch, it's not a switch: there's no fallthrough, you can't
put statements inside, etc.

The problem with all these proposals:

let thisColor = match thatColor
     case .Red: match thatOtherColor
                           case .Blue: .Green
                           case .Pink: .Yellow
                           default: .Orange
     default: .Orange

is ambiguous. (Does case .Pink match thatColor or thatOtherColor? We can
know because of exhaustiveness checking, but this won't always work.) You
could solve this problem either by using parentheses around the whole
expression when necessary

let thisColor = match thatColor
     case .Red: (match thatOtherColor
                           case .Blue: .Green
                           case .Pink: .Yellow
                           default: .Orange)
     default: .Orange

or by adding curly braces in again

let thisColor = match thatColor {
     case .Red: match thatOtherColor {
                           case .Blue: .Green
                           case .Pink: .Yellow
                           default: .Orange
                        }
     default: .Orange
}

But that starts to look like switch again. (Of course, the best way to
handle this is as a programmer is to just switch on the tuple (thatColor,
thatOtherColor), but the language should allow for nested control
expressions.)

···

On Sun, Dec 6, 2015 at 2:48 PM, Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

I am not a fan of this approach based on the ternary operator. The
ternary operator is already a bit of an anomaly in that all other operators
are unary or binary and do not perform any control flow (beyond possibly
short circuiting an autoclosure argument).

I would much rather features that perform control flow continue to use
keywords, but allow them to be expressions.

Once we have control flow expressions I would like to see the ternary
operator removed from the language as it would no longer server a purpose.
Removing the ternary operator seems to fit nicely with the direction to
remove some features that are carried over from C-based languages but don’t
necessarily fit with the direction Swift is heading.

On Dec 6, 2015, at 1:19 PM, Kevin Lundberg via swift-evolution < > swift-evolution@swift.org> wrote:

Ostensibly, case may not be necessary if you could delimit each case on
one line with something (perhaps a comma, or something else if that would
not fit well within the grammar):

let thisColor = thatColor ? .Blue: .Red, .Green: .Blue, .Red: .Green,
default: .Yellow

On Sun, Dec 6, 2015, at 01:57 PM, Paul Ossenbruggen via swift-evolution > wrote:

I like this too, seems more powerful. Also, would single line expressions
be allowed? If not would case be required for example:

let myFavoriteColor = yourFavoriteColor ?
    case .Blue: .Red
    case .Green: .Blue
    case .Red: .Green
    default: .Yellow

On Dec 6, 2015, at 9:11 AM, Sean Heber via swift-evolution < > swift-evolution@swift.org> wrote:

I really like this train of thought. +1

l8r
Sean

On Dec 6, 2015, at 11:02 AM, Alex Lew via swift-evolution < > swift-evolution@swift.org> wrote:

What if we left the if { ...} else { ... } syntax alone (as a statement),
and updated the ternary expression to be a more general pattern matching
expression (closer to "switch")? Something like

let x = condition ?
   true: "Hello"
   false: "Goodbye"

let x = optionalValue ?
   .Some(let unwrapped): "Hello, \(unwrapped)"
   .None: "To Whom It May Concern"

let myFavoriteColor = yourFavoriteColor ?
    .Blue: .Red
    .Green: .Blue
    .Red: .Green

let quadrant = (x, y) ?
    let (x, y) where x < 50 && y < 50: "top left"
    let (x, y) where x < 50 && y > 50: "bottom left"
    let (x, y) where x > 50 && y < 50: "top right"
    default: "bottom right"

The colon comes from the fact that this is sort of a light-weight
expression-based "switch" statement, where each branch can only contain an
expression, not a series of statements.

This is very similar to pattern matching expressions in languages like
Haskell, ML, and Coq.

On Sun, Dec 6, 2015 at 11:25 AM, Thorsten Seitz <thorsten.seitz@web.de> wrote:

Am 06.12.2015 um 01:28 schrieb Alex Lew via swift-evolution < > swift-evolution@swift.org>:

I don't think you can just get rid of the if statement in favor of an
expression. You still want to be able to do this:

if (condition) {
    funcWithSideEffectsThatReturnsInt()
} else {
    funcWithSideEffectsThatReturnsString()
}

but that's not a valid expression (what is its type?).

That would actually be no problem if Swift’s type system would have union
types (Ceylon has union and intersection types which are quite awesome and
enable lots of nice things quite naturally, see
Eclipse Ceylon™ | projects.eclipse.org).

In that case the type of such an expression would just be the union of
both types, which is written Int | String in Ceylon.

-Thorsten

_______________________________________________
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

Untracked with Trackbuster <Your contacts automatically up to date | evercontact;

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

In thinking about this, is there a way to have the compiler detect that something is a statement vs expression? Is it always clear to users when something is an expression vs a statement? In blurring the lines between expressions and statements complications arise anytime there is a return value returned by the result of “switch” or “if” it suddenly becomes an expression. Are there gray areas where it is hard to determine whether it is one vs the other when we use the those keywords? If it is not possible to determine for every situation or confusing to users, then maybe a new keyword for expressions is necessary. When a branch of an else returns void does it then become a statement? We should avoid shoehorning it in just to avoid another keyword.

let foo = if condition {
  x = 1 // implied void -- illegal
} else {
  10 // returns expression
}

also, I think this is confusing:

let foo = if condition {
  function1()
} else {
  function2()
}

it is not obvious that this is an assignment or that the functions return anything. Earlier I suggested something using = to make it more clear. This is similar to the requirement that functions that throw are prefixed with with “try"

let foo if condition {
  = function1()
} else {
  = function2()
}

also for the literal case:

let foo if condition {
  = 1 // can’t accidentally put a non expression here.
} else {
  = 10 // returns expression
}

Which makes it clear that it is an expression coming back from both sides of the “if”. The switch case is a little trickier because of the case.

let foo switch value {
  = .Red: function1()
  = .Green function2()
  = default: function3()
}

The equal emphasizes the functions return a value for each part of the switch and assigns to “foo”, but somehow is unsatisfying having that equal everywhere.

One the other hand, the ternary operator being an expression this confusion does not exist, it is clear that function1() and function2() must return a value.

let foo = condition ? function1() : function2()

even when on separate lines:

let foo = condition ?
  function1() :
  function2()

So maybe Alex’s original suggestion works better where the ? operator is extended to support a switch like expression and keeping the two statements and expressions separate.

let foo = condition ?
  .Red : .Green
  .Green : Red

let foo = condition ?
  .Red: function1()
  .Green: function2()

let foo = condition ? .Red: function1() .Blue: function2() default:. function3()

also could include optional cases:

let foo = condition ? case .Red: function1(), case .Blue: functions(), default: function3()

Which brings us back full circle to the keyword because most people don’t like the ? operator which is why Alex suggested “match":

let foo = match condition
  .Red: function1()
  .Green: function2()
  default: function3()

or with optional cases:

let foo = match condition
  case .Red: function1()
  case .Green: function2()
  default: function3()

for booleans :

let too = match condition function() else function2()

I still like this better. A new keyword makes sure there is no confusion about expressions vs statements and avoids complications with the return values. Match would always be an expression, if/else/swtich are always statements. Also those keywords don’t change behavior if a user changes a statement into an expression by assigning the expression the else part would suddenly be required.

if condition {
  function1()
}

is changed to

let foo = if condition {
  function1()
}

is now an error, because there is no else. Now if function1() does not return a value. you have another error just changing it to assign completely changes the behavior of the “if” statement.

- Paul

···

On Dec 6, 2015, at 2:11 PM, Paul Ossenbruggen <possen@gmail.com> wrote:

so the rule would have to be that the “switch" or “if" must return a value of compatible type. Not sure I love all the braces in the “if" case but it does follow the existing language rules with the exception that it must be have an else.

let thisColor = if condition { .Red } // illegal for expressions but not statements

Can still do this for statements:
if condition {
  x = 40
}

likewise:
let thisColor = if condition { .Red } else { 21 } // illegal unless thisColor is Any

unless:
let thisColor : Any = if condition { .Red } else { 21 } // illegal unless thisColor is Any

It would be nice to omit braces in this expression case but not for statements:
let thisColor = if condition .Red else .Blue

in statements braces would be required:

if condition {
  x = 32
} else {
  y = 44
}

> }
On Dec 6, 2015, at 1:52 PM, Alex Lew via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I agree that it's simplest to just reuse switch keyword, and keep braces. +1.

Would you allow the same thing with if?

let thisColor = if condition { .Red } else { .Blue }

On Sun, Dec 6, 2015 at 4:44 PM, Rudolf Adamkovic <salutis@me.com <mailto:salutis@me.com>> wrote:
> On 06 Dec 2015, at 22:35, thorsten--- via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

>
> I would prefer the expression to match the statement. The only difference would be that all parts that were statements now have to be expressions.

+1

>
> Therefore the switch-expression should simply look like follows:
>
> let thisColor = switch thatColor {
> case .Red: .Green // must be an expression
> default: .Yellow // must be an expression
> }
>
> No returns needed in the case clauses.

This actually looks great. One simple rule and zero new keywords.

Readable and simple to learn.

Fantastic!

> Formatting this as a one-liner would just require adding semicolons (though I wouldn't recommend this).
>
> -Thorsten
> _______________________________________________
> 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 also agree with this. I see no value in different syntax for statements and expressions, just unnecessary complexity.

Modifying the current syntax is an orthogonal issue. If anyone feels the current switch syntax is to verbose I would recommend writing a new proposal to change it. If such a proposal were adopted the new syntax should be used for both statements and expressions.

···

Sent from my iPhone

On Dec 6, 2015, at 4:14 PM, Alex Lew via swift-evolution <swift-evolution@swift.org> wrote:

:+1:

On Sun, Dec 6, 2015 at 5:12 PM, thorsten@portableinnovations.de <thorsten@portableinnovations.de> wrote:
Absolutely. Just the same rule: parts that were statements must be expressions. The else clause becomes mandatory.

-Thorsten

Am 06.12.2015 um 22:52 schrieb Alex Lew <alexl.mail+swift@gmail.com>:

I agree that it's simplest to just reuse switch keyword, and keep braces. +1.

Would you allow the same thing with if?

let thisColor = if condition { .Red } else { .Blue }

On Sun, Dec 6, 2015 at 4:44 PM, Rudolf Adamkovic <salutis@me.com> wrote:
> On 06 Dec 2015, at 22:35, thorsten--- via swift-evolution <swift-evolution@swift.org> wrote:

>
> I would prefer the expression to match the statement. The only difference would be that all parts that were statements now have to be expressions.

+1

>
> Therefore the switch-expression should simply look like follows:
>
> let thisColor = switch thatColor {
> case .Red: .Green // must be an expression
> default: .Yellow // must be an expression
> }
>
> No returns needed in the case clauses.

This actually looks great. One simple rule and zero new keywords.

Readable and simple to learn.

Fantastic!

> Formatting this as a one-liner would just require adding semicolons (though I wouldn't recommend this).
>
> -Thorsten
> _______________________________________________
> 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 would prefer the expression to match the statement. The only difference would be that all parts that were statements now have to be expressions.

Therefore the switch-expression should simply look like follows:

let thisColor = switch thatColor {
         case .Red: .Green // must be an expression
         default: .Yellow // must be an expression
     }

No returns needed in the case clauses.
Formatting this as a one-liner would just require adding semicolons (though I wouldn't recommend this).

-Thorsten

I strongly dislike the one liner with only punctuation to separate the cases because it is very difficult to spot the pairs.

I fail to see why we have to have new syntax for the expression case.

-Thorsten

···

Am 06.12.2015 um 21:30 schrieb Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org>:

let myColor = yourColor switch? .Blue : .Red, .Green: .Blue, .Red: .Green, default: .Yellow

Absolutely. Just the same rule: parts that were statements must be expressions. The else clause becomes mandatory.

-Thorsten

···

Am 06.12.2015 um 22:52 schrieb Alex Lew <alexl.mail+swift@gmail.com>:

I agree that it's simplest to just reuse switch keyword, and keep braces. +1.

Would you allow the same thing with if?

let thisColor = if condition { .Red } else { .Blue }

On Sun, Dec 6, 2015 at 4:44 PM, Rudolf Adamkovic <salutis@me.com> wrote:
> On 06 Dec 2015, at 22:35, thorsten--- via swift-evolution <swift-evolution@swift.org> wrote:

>
> I would prefer the expression to match the statement. The only difference would be that all parts that were statements now have to be expressions.

+1

>
> Therefore the switch-expression should simply look like follows:
>
> let thisColor = switch thatColor {
> case .Red: .Green // must be an expression
> default: .Yellow // must be an expression
> }
>
> No returns needed in the case clauses.

This actually looks great. One simple rule and zero new keywords.

Readable and simple to learn.

Fantastic!

> Formatting this as a one-liner would just require adding semicolons (though I wouldn't recommend this).
>
> -Thorsten
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

:+1:

···

On Sun, Dec 6, 2015 at 5:12 PM, thorsten@portableinnovations.de < thorsten@portableinnovations.de> wrote:

Absolutely. Just the same rule: parts that were statements must be
expressions. The else clause becomes mandatory.

-Thorsten

Am 06.12.2015 um 22:52 schrieb Alex Lew <alexl.mail+swift@gmail.com>:

I agree that it's simplest to just reuse switch keyword, and keep braces.
+1.

Would you allow the same thing with if?

let thisColor = if condition { .Red } else { .Blue }

On Sun, Dec 6, 2015 at 4:44 PM, Rudolf Adamkovic <salutis@me.com> wrote:

> On 06 Dec 2015, at 22:35, thorsten--- via swift-evolution < >> swift-evolution@swift.org> wrote:

>
> I would prefer the expression to match the statement. The only
difference would be that all parts that were statements now have to be
expressions.

+1

>
> Therefore the switch-expression should simply look like follows:
>
> let thisColor = switch thatColor {
> case .Red: .Green // must be an expression
> default: .Yellow // must be an expression
> }
>
> No returns needed in the case clauses.

This actually looks great. One simple rule and zero new keywords.

Readable and simple to learn.

Fantastic!

> Formatting this as a one-liner would just require adding semicolons
(though I wouldn't recommend this).
>
> -Thorsten
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

I would prefer the expression to match the statement. The only difference would be that all parts that were statements now have to be expressions.

+1

Therefore the switch-expression should simply look like follows:

let thisColor = switch thatColor {
        case .Red: .Green // must be an expression
        default: .Yellow // must be an expression
    }

No returns needed in the case clauses.

This actually looks great. One simple rule and zero new keywords.

Readable and simple to learn.

Fantastic!

···

On 06 Dec 2015, at 22:35, thorsten--- via swift-evolution <swift-evolution@swift.org> wrote:

Formatting this as a one-liner would just require adding semicolons (though I wouldn't recommend this).

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

I think the compiler can just assume that if it's valid to have a statement
in a given context, the if or switch should be interpreted as a statement.

A convention of keeping if-expressions to one line, and switch-expressions
to one line per case, would make things relatively readable (though I don't
feel that strongly about the convention):

let foo = if condition { function1() } else { function2() }
let foo = switch color {
    case .Red: function1()
    case .Green: function2()
    default: function3()
}

I'm still not totally convinced by Matthew's argument that making the
syntax lighter-weight is orthogonal to the expression/statement question.
In my mind, it makes sense to have both a heavier switch *statement*,
(which might have many sub-statements in each branch), and also a
lighter-weight option for a quick pattern-match inside an expression (like
the ones we've been discussing in this thread).

This is the whole idea behind the ternary operator in C, and the "a = value
if condition else otherValue" in Python, etc. That's why I kind of like the
ternary-operator-inspired syntax for pattern matching. It would be awful to
use for statements -- just like it would be awful to replace if/else
statements in C with the C ternary operator's syntax -- but I think it's
pretty readable for expressions. It just seems to fit: just like C's if,
while, for, and switch can now pattern match in Swift, so can ?: (not to
mention that the colons after each case "rhyme" with the original colon in
the ternary operator).

But I believe I'm in the minority on that opinion, which is totally fine. :)

I think the questions then become: first, as Chris has asked, do the
if/switch expressions provide enough of a benefit (in terms of conciseness)
to be worth implementing? And, as Matthew suggested: is there a
lighter-weight syntax that would make both statements and expressions more
succinct?

All best,
Alex

···

On Sun, Dec 6, 2015 at 10:11 PM, Paul Ossenbruggen <possen@gmail.com> wrote:

In thinking about this, is there a way to have the compiler detect that
something is a statement vs expression? Is it always clear to users when
something is an expression vs a statement? In blurring the lines between
expressions and statements complications arise anytime there is a return
value returned by the result of “switch” or “if” it suddenly becomes an
expression. Are there gray areas where it is hard to determine whether it
is one vs the other when we use the those keywords? If it is not possible
to determine for every situation or confusing to users, then maybe a new
keyword for expressions is necessary. When a branch of an else returns void
does it then become a statement? We should avoid shoehorning it in just to
avoid another keyword.

let foo = if condition {
x = 1 // implied void -- illegal
} else {
10 // returns expression
}

also, I think this is confusing:

let foo = if condition {
function1()
} else {
function2()
}

it is not obvious that this is an assignment or that the functions return
anything. Earlier I suggested something using = to make it more clear.
This is similar to the requirement that functions that throw are prefixed
with with “try"

let foo if condition {
= function1()
} else {
= function2()
}

also for the literal case:

let foo if condition {
= 1 // can’t accidentally put a non expression here.
} else {
= 10 // returns expression
}

Which makes it clear that it is an expression coming back from both sides
of the “if”. The switch case is a little trickier because of the case.

let foo switch value {
= .Red: function1()
= .Green function2()
= default: function3()
}

The equal emphasizes the functions return a value for each part of the
switch and assigns to “foo”, but somehow is unsatisfying having that equal
everywhere.

One the other hand, the ternary operator being an expression this
confusion does not exist, it is clear that function1() and function2() must
return a value.

let foo = condition ? function1() : function2()

even when on separate lines:

let foo = condition ?
function1() :
function2()

So maybe Alex’s original suggestion works better where the ? operator is
extended to support a switch like expression and keeping the two statements
and expressions separate.

let foo = condition ?
.Red : .Green
.Green : Red

let foo = condition ?
.Red: function1()
.Green: function2()

let foo = condition ? .Red: function1() .Blue: function2() default:.
function3()

also could include optional cases:

let foo = condition ? case .Red: function1(), case .Blue: functions(),
default: function3()

Which brings us back full circle to the keyword because most people don’t
like the ? operator which is why Alex suggested “match":

let foo = match condition
.Red: function1()
.Green: function2()
default: function3()

or with optional cases:

let foo = match condition
case .Red: function1()
case .Green: function2()
default: function3()

for booleans :

let too = match condition function() else function2()

I still like this better. A new keyword makes sure there is no confusion
about expressions vs statements and avoids complications with the return
values. Match would always be an expression, if/else/swtich are always
statements. Also those keywords don’t change behavior if a user changes a
statement into an expression by assigning the expression the else part
would suddenly be required.

if condition {
function1()
}

is changed to

let foo = if condition {
function1()
}

is now an error, because there is no else. Now if function1() does not
return a value. you have another error just changing it to assign
completely changes the behavior of the “if” statement.

- Paul

On Dec 6, 2015, at 2:11 PM, Paul Ossenbruggen < possen@gmail.com> wrote:

so the rule would have to be that the “switch" or “if" must return a value
of compatible type. Not sure I love all the braces in the “if" case but it
does follow the existing language rules with the exception that it must be
have an else.

let thisColor = if condition { .Red } // illegal for expressions but not
statements

Can still do this for statements:
if condition {
x = 40
}

likewise:
let thisColor = if condition { .Red } else { 21 } // illegal unless
thisColor is Any

unless:
let thisColor : Any = if condition { .Red } else { 21 } // illegal unless
thisColor is Any

It would be nice to omit braces in this expression case but not for
statements:
let thisColor = if condition .Red else .Blue

in statements braces would be required:

if condition {
x = 32
} else {
y = 44
}

> }

On Dec 6, 2015, at 1:52 PM, Alex Lew via swift-evolution < > swift-evolution@swift.org> wrote:

I agree that it's simplest to just reuse switch keyword, and keep braces.
+1.

Would you allow the same thing with if?

let thisColor = if condition { .Red } else { .Blue }

On Sun, Dec 6, 2015 at 4:44 PM, Rudolf Adamkovic <salutis@me.com> wrote:

> On 06 Dec 2015, at 22:35, thorsten--- via swift-evolution < >> swift-evolution@swift.org> wrote:

>
> I would prefer the expression to match the statement. The only
difference would be that all parts that were statements now have to be
expressions.

+1

>
> Therefore the switch-expression should simply look like follows:
>
> let thisColor = switch thatColor {
> case .Red: .Green // must be an expression
> default: .Yellow // must be an expression
> }
>
> No returns needed in the case clauses.

This actually looks great. One simple rule and zero new keywords.

Readable and simple to learn.

Fantastic!

> Formatting this as a one-liner would just require adding semicolons
(though I wouldn't recommend this).
>
> -Thorsten
> _______________________________________________
> 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 would indent multiline expressions, so that the assignment target stands out.

let foo = if condition {
            function1()
      } else {
            function2()
      }

Same for the switch-expression.

-Thorsten

···

Am 07.12.2015 um 04:11 schrieb Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org>:

let foo = if condition {
  function1()
} else {
  function2()
}

I agree that it's simplest to just reuse switch keyword, and keep braces.
+1.

Would you allow the same thing with if?

let thisColor = if condition { .Red } else { .Blue }

···

On Sun, Dec 6, 2015 at 4:44 PM, Rudolf Adamkovic <salutis@me.com> wrote:

> On 06 Dec 2015, at 22:35, thorsten--- via swift-evolution < > swift-evolution@swift.org> wrote:

>
> I would prefer the expression to match the statement. The only
difference would be that all parts that were statements now have to be
expressions.

+1

>
> Therefore the switch-expression should simply look like follows:
>
> let thisColor = switch thatColor {
> case .Red: .Green // must be an expression
> default: .Yellow // must be an expression
> }
>
> No returns needed in the case clauses.

This actually looks great. One simple rule and zero new keywords.

Readable and simple to learn.

Fantastic!

> Formatting this as a one-liner would just require adding semicolons
(though I wouldn't recommend this).
>
> -Thorsten
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

This is the whole idea behind the ternary operator in C, and the "a = value if condition else otherValue" in Python, etc. That's why I kind of like the ternary-operator-inspired syntax for pattern matching. It would be awful to use for statements -- just like it would be awful to replace if/else statements in C with the C ternary operator's syntax -- but I think it's pretty readable for expressions. It just seems to fit: just like C's if, while, for, and switch can now pattern match in Swift, so can ?: (not to mention that the colons after each case "rhyme" with the original colon in the ternary operator).

Agreed, I don’t mind the repurpose of the ? or match. I think there is real value in having expressions and switch like expressions. It avoids this problem:

switch x {
  case 1: let y = 5
  case 2: let y = 6
  case 3: let y = 7
  default: y = 8
}
print(y)

y is out of scope here so you currently have to write…

let y : Int
switch x {
  case 1: y = 5
  case 2: y = 6
  case 3: y = 7
  default: y = 8
}
print(y)

y is in scope feels more clumsy but an expression would be straight forward because type inference would take care or the result for you.

···

On Dec 6, 2015, at 7:45 PM, Alex Lew <alexl.mail+swift@gmail.com> wrote:

I think the compiler can just assume that if it's valid to have a statement in a given context, the if or switch should be interpreted as a statement.

A convention of keeping if-expressions to one line, and switch-expressions to one line per case, would make things relatively readable (though I don't feel that strongly about the convention):

let foo = if condition { function1() } else { function2() }
let foo = switch color {
    case .Red: function1()
    case .Green: function2()
    default: function3()
}

I'm still not totally convinced by Matthew's argument that making the syntax lighter-weight is orthogonal to the expression/statement question. In my mind, it makes sense to have both a heavier switch statement, (which might have many sub-statements in each branch), and also a lighter-weight option for a quick pattern-match inside an expression (like the ones we've been discussing in this thread).

This is the whole idea behind the ternary operator in C, and the "a = value if condition else otherValue" in Python, etc. That's why I kind of like the ternary-operator-inspired syntax for pattern matching. It would be awful to use for statements -- just like it would be awful to replace if/else statements in C with the C ternary operator's syntax -- but I think it's pretty readable for expressions. It just seems to fit: just like C's if, while, for, and switch can now pattern match in Swift, so can ?: (not to mention that the colons after each case "rhyme" with the original colon in the ternary operator).

But I believe I'm in the minority on that opinion, which is totally fine. :)

I think the questions then become: first, as Chris has asked, do the if/switch expressions provide enough of a benefit (in terms of conciseness) to be worth implementing? And, as Matthew suggested: is there a lighter-weight syntax that would make both statements and expressions more succinct?

All best,
Alex

On Sun, Dec 6, 2015 at 10:11 PM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:
In thinking about this, is there a way to have the compiler detect that something is a statement vs expression? Is it always clear to users when something is an expression vs a statement? In blurring the lines between expressions and statements complications arise anytime there is a return value returned by the result of “switch” or “if” it suddenly becomes an expression. Are there gray areas where it is hard to determine whether it is one vs the other when we use the those keywords? If it is not possible to determine for every situation or confusing to users, then maybe a new keyword for expressions is necessary. When a branch of an else returns void does it then become a statement? We should avoid shoehorning it in just to avoid another keyword.

let foo = if condition {
x = 1 // implied void -- illegal
} else {
10 // returns expression
}

also, I think this is confusing:

let foo = if condition {
function1()
} else {
function2()
}

it is not obvious that this is an assignment or that the functions return anything. Earlier I suggested something using = to make it more clear. This is similar to the requirement that functions that throw are prefixed with with “try"

let foo if condition {
= function1()
} else {
= function2()
}

also for the literal case:

let foo if condition {
= 1 // can’t accidentally put a non expression here.
} else {
= 10 // returns expression
}

Which makes it clear that it is an expression coming back from both sides of the “if”. The switch case is a little trickier because of the case.

let foo switch value {
= .Red: function1()
= .Green function2()
= default: function3()
}

The equal emphasizes the functions return a value for each part of the switch and assigns to “foo”, but somehow is unsatisfying having that equal everywhere.

One the other hand, the ternary operator being an expression this confusion does not exist, it is clear that function1() and function2() must return a value.

let foo = condition ? function1() : function2()

even when on separate lines:

let foo = condition ?
function1() :
function2()

So maybe Alex’s original suggestion works better where the ? operator is extended to support a switch like expression and keeping the two statements and expressions separate.

let foo = condition ?
.Red : .Green
.Green : Red

let foo = condition ?
.Red: function1()
.Green: function2()

let foo = condition ? .Red: function1() .Blue: function2() default:. function3()

also could include optional cases:

let foo = condition ? case .Red: function1(), case .Blue: functions(), default: function3()

Which brings us back full circle to the keyword because most people don’t like the ? operator which is why Alex suggested “match":

let foo = match condition
.Red: function1()
.Green: function2()
default: function3()

or with optional cases:

let foo = match condition
case .Red: function1()
case .Green: function2()
default: function3()

for booleans :

let too = match condition function() else function2()

I still like this better. A new keyword makes sure there is no confusion about expressions vs statements and avoids complications with the return values. Match would always be an expression, if/else/swtich are always statements. Also those keywords don’t change behavior if a user changes a statement into an expression by assigning the expression the else part would suddenly be required.

if condition {
function1()
}

is changed to

let foo = if condition {
function1()
}

is now an error, because there is no else. Now if function1() does not return a value. you have another error just changing it to assign completely changes the behavior of the “if” statement.

- Paul

On Dec 6, 2015, at 2:11 PM, Paul Ossenbruggen < possen@gmail.com <mailto:possen@gmail.com>> wrote:

so the rule would have to be that the “switch" or “if" must return a value of compatible type. Not sure I love all the braces in the “if" case but it does follow the existing language rules with the exception that it must be have an else.

let thisColor = if condition { .Red } // illegal for expressions but not statements

Can still do this for statements:
if condition {
x = 40
}

likewise:
let thisColor = if condition { .Red } else { 21 } // illegal unless thisColor is Any

unless:
let thisColor : Any = if condition { .Red } else { 21 } // illegal unless thisColor is Any

It would be nice to omit braces in this expression case but not for statements:
let thisColor = if condition .Red else .Blue

in statements braces would be required:

if condition {
x = 32
} else {
y = 44
}

> }
On Dec 6, 2015, at 1:52 PM, Alex Lew via swift-evolution < swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I agree that it's simplest to just reuse switch keyword, and keep braces. +1.

Would you allow the same thing with if?

let thisColor = if condition { .Red } else { .Blue }

On Sun, Dec 6, 2015 at 4:44 PM, Rudolf Adamkovic <salutis@me.com <mailto:salutis@me.com>> wrote:
> On 06 Dec 2015, at 22:35, thorsten--- via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

>
> I would prefer the expression to match the statement. The only difference would be that all parts that were statements now have to be expressions.

+1

>
> Therefore the switch-expression should simply look like follows:
>
> let thisColor = switch thatColor {
> case .Red: .Green // must be an expression
> default: .Yellow // must be an expression
> }
>
> No returns needed in the case clauses.

This actually looks great. One simple rule and zero new keywords.

Readable and simple to learn.

Fantastic!

> Formatting this as a one-liner would just require adding semicolons (though I wouldn't recommend this).
>
> -Thorsten
> _______________________________________________
> 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

Removing ?: is an excellent idea - but do we really need to replace it with anything new?
inline blocks seem to provide much more flexibility with the current language with no new keywords and a much clearer intent

let myColor = (
  match yourColor
  case .Blue: .Red
  case .Green: .Blue
  case .Red: .Blue
)

let myColor : Color = {
  switch (yourColor) {
    case .Red: return .Green
    case .Green: return .Blue
    case .Blue: return .Red
  }
}()

···

On 7 Dec 2015, at 16:06, thorsten--- via swift-evolution <swift-evolution@swift.org> wrote:

I would indent multiline expressions, so that the assignment target stands out.

let foo = if condition {
           function1()
     } else {
           function2()
     }

Same for the switch-expression.

-Thorsten

Am 07.12.2015 um 04:11 schrieb Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org>:

let foo = if condition {
  function1()
} else {
  function2()
}

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

Strong -1; this turns a quick one-liner into a multiline monstrosity. When massaging coordinates and layouts in iOS apps, ?: is often helpful to handle corner cases inline.

A.

Strong -1, for all the reasons Andrey gave, although I think his point could benefit from examples.

Consider this case from my codebase, for which ?: is natural:

    ///Signature Calculations for the Authorization Header: Transferring Payload in a Single Chunk (AWS Signature Version 4) - Amazon Simple Storage Service
   func uriEncode(string: String, encodeSlash: Bool) -> String {
        var encodedString = ""
        for char in string.characters {
            if (char >= "A" && char <= "z") || (char >= "a" && char <= "z") || (char >= "0" && char <= "9") || char == "_" || char == "-" || char == "~" || char == "." {
                encodedString += "\(char)"
            }
            else if char == "/" {
                encodedString += encodeSlash ? "%2F" : "\(char)"
            }
            else {
                let literal = String(char)
                for byte in literal.utf8 {
                    encodedString += String(format: "%%2X", arguments: [Int(byte)])
                }
            }
        }
        return encodedString
    }

I think replacing with `let foo` and scopes lengthens, emphasizes, and draws attention to a very minor detail, de-emphaizing and obscuring the main idea of the function.

···

On Dec 11, 2015, at 7:18 PM, Andrey Tarantsov via swift-evolution <swift-evolution@swift.org> wrote:

Strong -1; this turns a quick one-liner into a multiline monstrosity. When massaging coordinates and layouts in iOS apps, ?: is often helpful to handle corner cases inline.

A.

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

How about:

let v = if condition then “A" else “B"

No mysterious symbols or braces, or multiline monstrosity.

···

On 12 Dec 2015, at 01:18, Andrey Tarantsov via swift-evolution <swift-evolution@swift.org> wrote:

Strong -1; this turns a quick one-liner into a multiline monstrosity. When massaging coordinates and layouts in iOS apps, ?: is often helpful to handle corner cases inline.

A.

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

+1 I personally really like the if then expression. I think is cleaner and
this way we can have if else expressions with curly braces too. Introducing
the then keyword also could allow for switch expressions.

let result = switch (yourColor) {
               case .Red then 1
               case .Green then 2
               case .Blue then 3
          }

···

On Fri, Dec 11, 2015 at 5:31 PM, Al Skipp via swift-evolution < swift-evolution@swift.org> wrote:

How about:

let v = if condition then “A" else “B"

No mysterious symbols or braces, or multiline monstrosity.

> On 12 Dec 2015, at 01:18, Andrey Tarantsov via swift-evolution < > swift-evolution@swift.org> wrote:
>
> Strong -1; this turns a quick one-liner into a multiline monstrosity.
When massaging coordinates and layouts in iOS apps, ?: is often helpful to
handle corner cases inline.
>
> A.
>
> _______________________________________________
> 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 think replacing with `let foo` and scopes lengthens, emphasizes, and draws attention to a very minor detail, de-emphaizing and obscuring the main idea of the function.

This.

How about:

let v = if condition then “A" else “B"

I don't think introducing a separate "then" keyword is a good idea, two subtly different kinds of IFs would be confusing.

I guess you meant:

let v = if condition { "A" } else { "B" }

That's acceptable to me, although might not be any more readable, and feels slightly inferior to:

let v = (condition ? "A" : "B")

A.