ternary operator ?: suggestion


(Alex Lew) #1

Hmm. Something about braces inside expressions just feels wrong to me.

I also read switch? and if? as being some optional-related versions of
switch and if. And I don't love putting the condition /
value-to-switch-on *before
*the keyword, if we're going to use a keyword.

(Also: exhaustiveness checking *could *theoretically allow resolution of
ambiguity in nested switch expressions. We would just have to require that
as soon as you've exhausted all possibilities, you don't add more cases and
the expression is over.)

···

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

Yep probably does need braces: So for switch? if? suggestion i just made.

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

let myColor = yourColor switch? { case .Blue : .Red; case .Green: .Blue;
case .Red: .Green; default: .Yellow }

let myColor = yourColor switch? {
case .Blue : .Reds
case .Green: .Blue
case .Red: .Green
default: .Yellow
}

let myColor = yourColor switch? {
.Blue : .Reds
.Green: .Blue
.Red: .Green
default: .Yellow
}

let myColor = condition if? { .Blue; .Red }

I don’t find that looks bad.

- Paul

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

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
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

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

Untracked with Trackbuster <https://trackbuster.com/?sig>

_______________________________________________
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


(Paul Ossenbruggen) #2

I agree that ? may imply optional, this may be similar to what you suggested, just filling in the example: Not sure parenthesis are better than braces though:

et myColor = match yourColor ( .Blue : .Red, .Green: .Blue, .Red: .Green, default: .Yellow )

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

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

let myColor = match yourColor (
  .Blue : .Reds
  .Green: .Blue
  .Red: .Green
  default: .Yellow
)

let myColor = match boollCondition ( .Blue, .Red )

···

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

Hmm. Something about braces inside expressions just feels wrong to me.

I also read switch? and if? as being some optional-related versions of switch and if. And I don't love putting the condition / value-to-switch-on before the keyword, if we're going to use a keyword.

(Also: exhaustiveness checking could theoretically allow resolution of ambiguity in nested switch expressions. We would just have to require that as soon as you've exhausted all possibilities, you don't add more cases and the expression is over.)

On Sun, Dec 6, 2015 at 3:46 PM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:
Yep probably does need braces: So for switch? if? suggestion i just made.

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

let myColor = yourColor switch? { case .Blue : .Red; case .Green: .Blue; case .Red: .Green; default: .Yellow }

let myColor = yourColor switch? {
  case .Blue : .Reds
  case .Green: .Blue
  case .Red: .Green
  default: .Yellow
}

let myColor = yourColor switch? {
  .Blue : .Reds
  .Green: .Blue
  .Red: .Green
  default: .Yellow
}

let myColor = condition if? { .Blue; .Red }

I don’t find that looks bad.

- Paul

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

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 <mailto: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 <mailto: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 <mailto: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 <mailto: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 <mailto:thorsten.seitz@web.de>> wrote:

Am 06.12.2015 um 01:28 schrieb Alex Lew via swift-evolution <swift-evolution@swift.org <mailto: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 <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

Untracked with Trackbuster <https://trackbuster.com/?sig>
_______________________________________________
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


(Alex Lew) #3

To clarify, I would want parens around the entire expression (only when
necessary). So

let myColor = match yourColor
case .Blue : .Red
case .Green: .Blue
case .Red: .Green
default: .Yellow

or

let myColor = match boolCondition
  case true: .Blue
  case false: .Red

or

let myColor = match boolCondition
  case true: (match yourColor
                      case .Red: .Blue
                      default: .Yellow)
  case false: .Red

But I actually think that the parens are unnecessary, as long as we require
matches to be exhaustive and for there to be no unreachable cases.

···

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

I agree that ? may imply optional, this may be similar to what you
suggested, just filling in the example: Not sure parenthesis are better
than braces though:

et myColor = match yourColor ( .Blue : .Red, .Green: .Blue, .Red: .Green,
default: .Yellow )

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

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

let myColor = match yourColor (
.Blue : .Reds
.Green: .Blue
.Red: .Green
default: .Yellow
)

let myColor = match boollCondition ( .Blue, .Red )

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

Hmm. Something about braces inside expressions just feels wrong to me.

I also read switch? and if? as being some optional-related versions of
switch and if. And I don't love putting the condition / value-to-switch-on *before
*the keyword, if we're going to use a keyword.

(Also: exhaustiveness checking *could *theoretically allow resolution of
ambiguity in nested switch expressions. We would just have to require that
as soon as you've exhausted all possibilities, you don't add more cases and
the expression is over.)

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

Yep probably does need braces: So for switch? if? suggestion i just
made.

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

let myColor = yourColor switch? { case .Blue : .Red; case .Green: .Blue;
case .Red: .Green; default: .Yellow }

let myColor = yourColor switch? {
case .Blue : .Reds
case .Green: .Blue
case .Red: .Green
default: .Yellow
}

let myColor = yourColor switch? {
.Blue : .Reds
.Green: .Blue
.Red: .Green
default: .Yellow
}

let myColor = condition if? { .Blue; .Red }

I don’t find that looks bad.

- Paul

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

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
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

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

Untracked with Trackbuster <https://trackbuster.com/?sig>

_______________________________________________
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 <https://trackbuster.com/?sig>


(Paul Ossenbruggen) #4

Got ya, so for a more complex example:

let myColor = (match yourColor
  case .Blue : .Reds
  case .Green: .Blue
  case .Red: match shade .LightRed : LightGreen, .MediumRed : .DarkGreen : DarkRed
  default: .Yellow
)

for booleans I would not want to list the true false cases out though.

let myColor = match boolCondition .Blue, .Red

···

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

To clarify, I would want parens around the entire expression (only when necessary). So

let myColor = match yourColor
case .Blue : .Red
case .Green: .Blue
case .Red: .Green
default: .Yellow

or

let myColor = match boolCondition
  case true: .Blue
  case false: .Red

or

let myColor = match boolCondition
  case true: (match yourColor
                      case .Red: .Blue
                      default: .Yellow)
  case false: .Red

But I actually think that the parens are unnecessary, as long as we require matches to be exhaustive and for there to be no unreachable cases.

On Sun, Dec 6, 2015 at 4:17 PM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:
I agree that ? may imply optional, this may be similar to what you suggested, just filling in the example: Not sure parenthesis are better than braces though:

et myColor = match yourColor ( .Blue : .Red, .Green: .Blue, .Red: .Green, default: .Yellow )

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

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

let myColor = match yourColor (
  .Blue : .Reds
.Green: .Blue
.Red: .Green
default: .Yellow
)

let myColor = match boollCondition ( .Blue, .Red )

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

Hmm. Something about braces inside expressions just feels wrong to me.

I also read switch? and if? as being some optional-related versions of switch and if. And I don't love putting the condition / value-to-switch-on before the keyword, if we're going to use a keyword.

(Also: exhaustiveness checking could theoretically allow resolution of ambiguity in nested switch expressions. We would just have to require that as soon as you've exhausted all possibilities, you don't add more cases and the expression is over.)

On Sun, Dec 6, 2015 at 3:46 PM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:
Yep probably does need braces: So for switch? if? suggestion i just made.

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

let myColor = yourColor switch? { case .Blue : .Red; case .Green: .Blue; case .Red: .Green; default: .Yellow }

let myColor = yourColor switch? {
case .Blue : .Reds
  case .Green: .Blue
case .Red: .Green
default: .Yellow
}

let myColor = yourColor switch? {
.Blue : .Reds
.Green: .Blue
.Red: .Green
default: .Yellow
}

let myColor = condition if? { .Blue; .Red }

I don’t find that looks bad.

- Paul

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

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 <mailto: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 <mailto: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 <mailto: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 <mailto: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 <mailto:thorsten.seitz@web.de>> wrote:

Am 06.12.2015 um 01:28 schrieb Alex Lew via swift-evolution <swift-evolution@swift.org <mailto: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 <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

Untracked with Trackbuster <https://trackbuster.com/?sig>
_______________________________________________
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

Untracked with Trackbuster <https://trackbuster.com/?sig>