ternary operator ?: suggestion

This is essentially the latest proposal that Paul offered.

The most similar proposal in his last mail seemed to be the following:

let b = switch(colorEnum then .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x00000FF, default: 0xFFFFFF)

This is quite different from the normal switch-syntax: parentheses instead of braces, "then" instead of "case" and only used once at the beginning while cases are separated by commas.

Apologies if I overlooked something.

-Thorsten

···

Am 22.12.2015 um 19:30 schrieb Félix Cloutier <felixcca@yahoo.ca>:

Félix

Le 22 déc. 2015 à 13:11:37, Thorsten Seitz <tseitz42@icloud.com> a écrit :

I still don't understand why we are not simply writing

let i = switch color {
        case .Red: 0xFF0000
        case .Green: 0x00FF00
        case .Blue: 0x00000FF
    }

No additional keywords, no wondering why different keywords and different syntax is used for something so similar. And not really longer than the alternative proposals (I do not count swapping "case" with "?" to be a gain, especially not if it requires to add a comma after each case).

-Thorsten

Am 22.12.2015 um 15:31 schrieb Charles Constant via swift-evolution <swift-evolution@swift.org>:

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

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

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

You forgot to declare the type, which is mandatory if you want to use
abbreviated cases like ".Red" to construct a one-off like that. That's one
of the reasons I complained that using a Dictionary is not a pleasant
alternative earlier on. The proposal ought to infer the enum Type, just
like a normal Switch statement.

On top of that, the limitations you mention also limit usefulness.

If it weren't for these issues, it would be good enough for me.

I know, but that won't support pattern matching.

Félix

···

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com <mailto:charles@charlesism.com>> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

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

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

Mea culpa: you were correct, this actually *does* work in a Playground, as
long as you access it when you construct it.

I didn't realize Swift was smart enough to infer a one-off Dict by its key.
Thanks Lattner & co! That is extremely cool :)

So that just leaves the fact that the Keys need to be hashable / not
optional.

Been thinking about the boolean case a bit more, and how to make it better than a ternary using my proposed syntax. So else could be put there to help show it is the opposite. The downside is this makes it mix keywords and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)
alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.
or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)
Any thoughts?

···

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com <mailto:charles@charlesism.com>> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

_______________________________________________
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

Some more ideas, this moves away from the notion that we should make it look really close to the ternary but keeps all the benefits of the ternary and improves upon it. Since I have been suggesting a breaking change, it is a good time to rethink it a bit. With this idea a horizontal line (double-dash) separates the control value from the choices, the vertical line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works here, where you can think of it as a numerical index. The advantage of this is, it stands out better and leaves ? for optionals only. This works well with the list form. In the enum case the index is the enum key. I can see that this however may be a problem because # is used for preprocessor like directives. I am suggesting though just the #( sequence is treated differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !( which could be read as "match stick” paren, where the word “match” matches a case, I am pretty sure that would not be considered any better than ?( because it is used for optionals. Another is “witch hat paren” ^( which can be read as “which”. This might create a parse problem with "power of" though, which maybe using ^[ (hat square bracket) could resolve that but not sure if that would create other problems. Some other choices would be &( and @( but did not choose them because they don’t have meaning to me but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF | 0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF
              > 0xFFFFFF) // enum multiline, default: can be used here if preferred.
let fe = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF) // if all cases handled, the last bar is optional

This visually kind of represents what is going on. Horizontal-line directs eye to one of the normal choices. Vertical-line says none found stop looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places where a ternary could be used. So it needs to work on a single line (and multiline) and needs to be compact. By having a compact, “else" that is possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary does.
• The horizontal line serves to provide a place to align the choices to pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or “default” choice, the colon does that in ternary but the bar stands out more.
• The parens group the expression, in a way that the ternary does not. With a ternary it is not until you get to the question mark and the barely visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a ternary.
• #( clearly show beginning and end of the construct so that it is immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with vertical bar like ternary but more visible. This also differs from the switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned as a problem in previous designs.
• All data types for the control are handled the same way, like ternary but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples). Which ternary does not.
• The vast majority of switch statements, at least that I typically use, could be done with this and be much more compact and concise. However if your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch statements used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement assigning an expression result.
• It makes it clear that the result of the expression can be a “let” where less experienced users may think a “var" is required in a switch statement.
• The name binding and assignment occurs in one step unlike the switch statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for multiline and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals only in single expressions for each case. There can only be one expression that gets selected by the control input. This simplifies things compared to a switch statement there are not multiple statements to list afterwards and it does not need the word “case" before each part of the choice to separate each list of statements. This makes it so that it can be much more compact and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
             .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010
     .Red: 0xFF0000
     .Green: 0x00FF00
     .Blue: 0x0000FF
     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I don’t think it is necessary: To make this kind of formatting easy, the editor should help align with the dashes. To allow more space on each line this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF

···

0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com> wrote:

Been thinking about the boolean case a bit more, and how to make it better than a ternary using my proposed syntax. So else could be put there to help show it is the opposite. The downside is this makes it mix keywords and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)
alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.
or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)
Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com <mailto:charles@charlesism.com>> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

_______________________________________________
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

Any feedback on this? I am rethinking the idea of #( because of the # prior usage as a preprocessor directive, but like how it stands out and has a meaning. If no feedback, does it make sense to update my proposal with these ideas? Or does this feel like the wrong direction.

···

On Dec 30, 2015, at 8:52 AM, Paul Ossenbruggen <possen@gmail.com> wrote:

Some more ideas, this moves away from the notion that we should make it look really close to the ternary but keeps all the benefits of the ternary and improves upon it. Since I have been suggesting a breaking change, it is a good time to rethink it a bit. With this idea a horizontal line (double-dash) separates the control value from the choices, the vertical line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works here, where you can think of it as a numerical index. The advantage of this is, it stands out better and leaves ? for optionals only. This works well with the list form. In the enum case the index is the enum key. I can see that this however may be a problem because # is used for preprocessor like directives. I am suggesting though just the #( sequence is treated differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !( which could be read as "match stick” paren, where the word “match” matches a case, I am pretty sure that would not be considered any better than ?( because it is used for optionals. Another is “witch hat paren” ^( which can be read as “which”. This might create a parse problem with "power of" though, which maybe using ^[ (hat square bracket) could resolve that but not sure if that would create other problems. Some other choices would be &( and @( but did not choose them because they don’t have meaning to me but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF | 0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF
              > 0xFFFFFF) // enum multiline, default: can be used here if preferred.
let fe = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF) // if all cases handled, the last bar is optional

This visually kind of represents what is going on. Horizontal-line directs eye to one of the normal choices. Vertical-line says none found stop looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places where a ternary could be used. So it needs to work on a single line (and multiline) and needs to be compact. By having a compact, “else" that is possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary does.
• The horizontal line serves to provide a place to align the choices to pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or “default” choice, the colon does that in ternary but the bar stands out more.
• The parens group the expression, in a way that the ternary does not. With a ternary it is not until you get to the question mark and the barely visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a ternary.
• #( clearly show beginning and end of the construct so that it is immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with vertical bar like ternary but more visible. This also differs from the switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned as a problem in previous designs.
• All data types for the control are handled the same way, like ternary but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples). Which ternary does not.
• The vast majority of switch statements, at least that I typically use, could be done with this and be much more compact and concise. However if your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch statements used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement assigning an expression result.
• It makes it clear that the result of the expression can be a “let” where less experienced users may think a “var" is required in a switch statement.
• The name binding and assignment occurs in one step unlike the switch statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for multiline and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals only in single expressions for each case. There can only be one expression that gets selected by the control input. This simplifies things compared to a switch statement there are not multiple statements to list afterwards and it does not need the word “case" before each part of the choice to separate each list of statements. This makes it so that it can be much more compact and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
             .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010
     .Red: 0xFF0000
     .Green: 0x00FF00
     .Blue: 0x0000FF
     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I don’t think it is necessary: To make this kind of formatting easy, the editor should help align with the dashes. To allow more space on each line this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF
> 0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Been thinking about the boolean case a bit more, and how to make it better than a ternary using my proposed syntax. So else could be put there to help show it is the opposite. The downside is this makes it mix keywords and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)
alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.
or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)
Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com <mailto:charles@charlesism.com>> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

_______________________________________________
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

-1 for me. None of it looks or feels like Swift, more like Haskell. I would prefer a library solution for now and remove ?: from the language and add a which into the standard library and see how that goes and if there is need for more.

Sorry,

Howard.

···

On 5 Jan 2016, at 7:24 AM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org> wrote:

Any feedback on this? I am rethinking the idea of #( because of the # prior usage as a preprocessor directive, but like how it stands out and has a meaning. If no feedback, does it make sense to update my proposal with these ideas? Or does this feel like the wrong direction.

On Dec 30, 2015, at 8:52 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Some more ideas, this moves away from the notion that we should make it look really close to the ternary but keeps all the benefits of the ternary and improves upon it. Since I have been suggesting a breaking change, it is a good time to rethink it a bit. With this idea a horizontal line (double-dash) separates the control value from the choices, the vertical line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works here, where you can think of it as a numerical index. The advantage of this is, it stands out better and leaves ? for optionals only. This works well with the list form. In the enum case the index is the enum key. I can see that this however may be a problem because # is used for preprocessor like directives. I am suggesting though just the #( sequence is treated differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !( which could be read as "match stick” paren, where the word “match” matches a case, I am pretty sure that would not be considered any better than ?( because it is used for optionals. Another is “witch hat paren” ^( which can be read as “which”. This might create a parse problem with "power of" though, which maybe using ^[ (hat square bracket) could resolve that but not sure if that would create other problems. Some other choices would be &( and @( but did not choose them because they don’t have meaning to me but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF | 0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF
              > 0xFFFFFF) // enum multiline, default: can be used here if preferred.
let fe = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF) // if all cases handled, the last bar is optional

This visually kind of represents what is going on. Horizontal-line directs eye to one of the normal choices. Vertical-line says none found stop looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places where a ternary could be used. So it needs to work on a single line (and multiline) and needs to be compact. By having a compact, “else" that is possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary does.
• The horizontal line serves to provide a place to align the choices to pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or “default” choice, the colon does that in ternary but the bar stands out more.
• The parens group the expression, in a way that the ternary does not. With a ternary it is not until you get to the question mark and the barely visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a ternary.
• #( clearly show beginning and end of the construct so that it is immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with vertical bar like ternary but more visible. This also differs from the switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned as a problem in previous designs.
• All data types for the control are handled the same way, like ternary but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples). Which ternary does not.
• The vast majority of switch statements, at least that I typically use, could be done with this and be much more compact and concise. However if your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch statements used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement assigning an expression result.
• It makes it clear that the result of the expression can be a “let” where less experienced users may think a “var" is required in a switch statement.
• The name binding and assignment occurs in one step unlike the switch statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for multiline and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals only in single expressions for each case. There can only be one expression that gets selected by the control input. This simplifies things compared to a switch statement there are not multiple statements to list afterwards and it does not need the word “case" before each part of the choice to separate each list of statements. This makes it so that it can be much more compact and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
             .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010
     .Red: 0xFF0000
     .Green: 0x00FF00
     .Blue: 0x0000FF
     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I don’t think it is necessary: To make this kind of formatting easy, the editor should help align with the dashes. To allow more space on each line this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF
> 0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Been thinking about the boolean case a bit more, and how to make it better than a ternary using my proposed syntax. So else could be put there to help show it is the opposite. The downside is this makes it mix keywords and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)
alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.
or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)
Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com <mailto:charles@charlesism.com>> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

_______________________________________________
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

Just tried going down this path a bit of creating a library. You can get pretty far for the boolean or integer types, but don’t see a way to do a switch like solution. Also, a big problem with this approach is there is no way to short circuit evaluate the expressions in the list of a variadic function. They will all be evaluated, at the call site. One other problem, so we don’t conflict with the “else” and “default”, keywords, I had to use “def” or “el” for “else".

// Simple bool
func calcB()->String {
    print(“B calculated")
    return "B"
}

// Simple bool
func sel<T>(condition : Bool, @autoclosure _ trueExpr:()->T, @autoclosure _ falseExpr:()->T) -> T {
    return condition ? trueExpr() : falseExpr()
}

sel(true, "A", calcB())
sel(false, "A", calcB())

// alternative, used "def" for default to not conflict with "else" or “default. This version, may not be necessary.
func sel<T>(condition : Bool, @autoclosure _ expr:()->T, @autoclosure el:()->T) -> T {
    return condition ? expr() : el()
}

sel(true, "A", el:calcB())
sel(false, "A", el:calcB())

// index approach, note the use of autoclosure does not work on array or array of functions. So it will evaluate all expressions at the call site. Unless there is some trick I don’t know.
func sel<T>(selector : Int,/* @autoclosure */ _ exprs: T..., def : T) -> T {
    if selector > exprs.count || selector < 0 {
        return def
    }
    return exprs[selector]
}
sel(1, "A", "B", "C", def:"D")
sel(9, "A", "B", "C", def:"D")
sel(-1, "A", "B", "C", def:"D")

···

On Jan 4, 2016, at 12:28 PM, Howard Lovatt <howard.lovatt@gmail.com> wrote:

-1 for me. None of it looks or feels like Swift, more like Haskell. I would prefer a library solution for now and remove ?: from the language and add a which into the standard library and see how that goes and if there is need for more.

Sorry,

Howard.

On 5 Jan 2016, at 7:24 AM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Any feedback on this? I am rethinking the idea of #( because of the # prior usage as a preprocessor directive, but like how it stands out and has a meaning. If no feedback, does it make sense to update my proposal with these ideas? Or does this feel like the wrong direction.

On Dec 30, 2015, at 8:52 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Some more ideas, this moves away from the notion that we should make it look really close to the ternary but keeps all the benefits of the ternary and improves upon it. Since I have been suggesting a breaking change, it is a good time to rethink it a bit. With this idea a horizontal line (double-dash) separates the control value from the choices, the vertical line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works here, where you can think of it as a numerical index. The advantage of this is, it stands out better and leaves ? for optionals only. This works well with the list form. In the enum case the index is the enum key. I can see that this however may be a problem because # is used for preprocessor like directives. I am suggesting though just the #( sequence is treated differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !( which could be read as "match stick” paren, where the word “match” matches a case, I am pretty sure that would not be considered any better than ?( because it is used for optionals. Another is “witch hat paren” ^( which can be read as “which”. This might create a parse problem with "power of" though, which maybe using ^[ (hat square bracket) could resolve that but not sure if that would create other problems. Some other choices would be &( and @( but did not choose them because they don’t have meaning to me but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF | 0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF
              > 0xFFFFFF) // enum multiline, default: can be used here if preferred.
let fe = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF) // if all cases handled, the last bar is optional

This visually kind of represents what is going on. Horizontal-line directs eye to one of the normal choices. Vertical-line says none found stop looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places where a ternary could be used. So it needs to work on a single line (and multiline) and needs to be compact. By having a compact, “else" that is possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary does.
• The horizontal line serves to provide a place to align the choices to pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or “default” choice, the colon does that in ternary but the bar stands out more.
• The parens group the expression, in a way that the ternary does not. With a ternary it is not until you get to the question mark and the barely visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a ternary.
• #( clearly show beginning and end of the construct so that it is immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with vertical bar like ternary but more visible. This also differs from the switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned as a problem in previous designs.
• All data types for the control are handled the same way, like ternary but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples). Which ternary does not.
• The vast majority of switch statements, at least that I typically use, could be done with this and be much more compact and concise. However if your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch statements used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement assigning an expression result.
• It makes it clear that the result of the expression can be a “let” where less experienced users may think a “var" is required in a switch statement.
• The name binding and assignment occurs in one step unlike the switch statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for multiline and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals only in single expressions for each case. There can only be one expression that gets selected by the control input. This simplifies things compared to a switch statement there are not multiple statements to list afterwards and it does not need the word “case" before each part of the choice to separate each list of statements. This makes it so that it can be much more compact and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
             .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010
     .Red: 0xFF0000
     .Green: 0x00FF00
     .Blue: 0x0000FF
     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I don’t think it is necessary: To make this kind of formatting easy, the editor should help align with the dashes. To allow more space on each line this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF
> 0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Been thinking about the boolean case a bit more, and how to make it better than a ternary using my proposed syntax. So else could be put there to help show it is the opposite. The downside is this makes it mix keywords and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)
alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.
or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)
Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com <mailto:charles@charlesism.com>> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

_______________________________________________
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

So without additional language support, I don’t see a library is workable but maybe it can. Maybe we can add variadic function lists? And new capabilities that are building blocks for building a switch expression.

···

On Jan 4, 2016, at 3:53 PM, Paul Ossenbruggen <possen@gmail.com> wrote:

Just tried going down this path a bit of creating a library. You can get pretty far for the boolean or integer types, but don’t see a way to do a switch like solution. Also, a big problem with this approach is there is no way to short circuit evaluate the expressions in the list of a variadic function. They will all be evaluated, at the call site. One other problem, so we don’t conflict with the “else” and “default”, keywords, I had to use “def” or “el” for “else".

// Simple bool
func calcB()->String {
    print(“B calculated")
    return "B"
}

// Simple bool
func sel<T>(condition : Bool, @autoclosure _ trueExpr:()->T, @autoclosure _ falseExpr:()->T) -> T {
    return condition ? trueExpr() : falseExpr()
}

sel(true, "A", calcB())
sel(false, "A", calcB())

// alternative, used "def" for default to not conflict with "else" or “default. This version, may not be necessary.
func sel<T>(condition : Bool, @autoclosure _ expr:()->T, @autoclosure el:()->T) -> T {
    return condition ? expr() : el()
}

sel(true, "A", el:calcB())
sel(false, "A", el:calcB())

// index approach, note the use of autoclosure does not work on array or array of functions. So it will evaluate all expressions at the call site. Unless there is some trick I don’t know.
func sel<T>(selector : Int,/* @autoclosure */ _ exprs: T..., def : T) -> T {
    if selector > exprs.count || selector < 0 {
        return def
    }
    return exprs[selector]
}
sel(1, "A", "B", "C", def:"D")
sel(9, "A", "B", "C", def:"D")
sel(-1, "A", "B", "C", def:"D")

On Jan 4, 2016, at 12:28 PM, Howard Lovatt <howard.lovatt@gmail.com <mailto:howard.lovatt@gmail.com>> wrote:

-1 for me. None of it looks or feels like Swift, more like Haskell. I would prefer a library solution for now and remove ?: from the language and add a which into the standard library and see how that goes and if there is need for more.

Sorry,

Howard.

On 5 Jan 2016, at 7:24 AM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Any feedback on this? I am rethinking the idea of #( because of the # prior usage as a preprocessor directive, but like how it stands out and has a meaning. If no feedback, does it make sense to update my proposal with these ideas? Or does this feel like the wrong direction.

On Dec 30, 2015, at 8:52 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Some more ideas, this moves away from the notion that we should make it look really close to the ternary but keeps all the benefits of the ternary and improves upon it. Since I have been suggesting a breaking change, it is a good time to rethink it a bit. With this idea a horizontal line (double-dash) separates the control value from the choices, the vertical line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works here, where you can think of it as a numerical index. The advantage of this is, it stands out better and leaves ? for optionals only. This works well with the list form. In the enum case the index is the enum key. I can see that this however may be a problem because # is used for preprocessor like directives. I am suggesting though just the #( sequence is treated differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !( which could be read as "match stick” paren, where the word “match” matches a case, I am pretty sure that would not be considered any better than ?( because it is used for optionals. Another is “witch hat paren” ^( which can be read as “which”. This might create a parse problem with "power of" though, which maybe using ^[ (hat square bracket) could resolve that but not sure if that would create other problems. Some other choices would be &( and @( but did not choose them because they don’t have meaning to me but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF | 0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF
              > 0xFFFFFF) // enum multiline, default: can be used here if preferred.
let fe = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF) // if all cases handled, the last bar is optional

This visually kind of represents what is going on. Horizontal-line directs eye to one of the normal choices. Vertical-line says none found stop looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places where a ternary could be used. So it needs to work on a single line (and multiline) and needs to be compact. By having a compact, “else" that is possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary does.
• The horizontal line serves to provide a place to align the choices to pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or “default” choice, the colon does that in ternary but the bar stands out more.
• The parens group the expression, in a way that the ternary does not. With a ternary it is not until you get to the question mark and the barely visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a ternary.
• #( clearly show beginning and end of the construct so that it is immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with vertical bar like ternary but more visible. This also differs from the switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned as a problem in previous designs.
• All data types for the control are handled the same way, like ternary but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples). Which ternary does not.
• The vast majority of switch statements, at least that I typically use, could be done with this and be much more compact and concise. However if your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch statements used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement assigning an expression result.
• It makes it clear that the result of the expression can be a “let” where less experienced users may think a “var" is required in a switch statement.
• The name binding and assignment occurs in one step unlike the switch statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for multiline and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals only in single expressions for each case. There can only be one expression that gets selected by the control input. This simplifies things compared to a switch statement there are not multiple statements to list afterwards and it does not need the word “case" before each part of the choice to separate each list of statements. This makes it so that it can be much more compact and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
             .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010
     .Red: 0xFF0000
     .Green: 0x00FF00
     .Blue: 0x0000FF
     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I don’t think it is necessary: To make this kind of formatting easy, the editor should help align with the dashes. To allow more space on each line this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF
> 0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Been thinking about the boolean case a bit more, and how to make it better than a ternary using my proposed syntax. So else could be put there to help show it is the opposite. The downside is this makes it mix keywords and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)
alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.
or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)
Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com <mailto:charles@charlesism.com>> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

_______________________________________________
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

In addition to the problems that you already cited, a library could not check exhaustiveness and we would lose pattern matching.

-Thorsten

···

Am 05.01.2016 um 00:53 schrieb Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org>:

Just tried going down this path a bit of creating a library. You can get pretty far for the boolean or integer types, but don’t see a way to do a switch like solution. Also, a big problem with this approach is there is no way to short circuit evaluate the expressions in the list of a variadic function. They will all be evaluated, at the call site. One other problem, so we don’t conflict with the “else” and “default”, keywords, I had to use “def” or “el” for “else".

// Simple bool
func calcB()->String {
    print(“B calculated")
    return "B"
}

// Simple bool
func sel<T>(condition : Bool, @autoclosure _ trueExpr:()->T, @autoclosure _ falseExpr:()->T) -> T {
    return condition ? trueExpr() : falseExpr()
}

sel(true, "A", calcB())
sel(false, "A", calcB())

// alternative, used "def" for default to not conflict with "else" or “default. This version, may not be necessary.
func sel<T>(condition : Bool, @autoclosure _ expr:()->T, @autoclosure el:()->T) -> T {
    return condition ? expr() : el()
}

sel(true, "A", el:calcB())
sel(false, "A", el:calcB())

// index approach, note the use of autoclosure does not work on array or array of functions. So it will evaluate all expressions at the call site. Unless there is some trick I don’t know.
func sel<T>(selector : Int,/* @autoclosure */ _ exprs: T..., def : T) -> T {
    if selector > exprs.count || selector < 0 {
        return def
    }
    return exprs[selector]
}
sel(1, "A", "B", "C", def:"D")
sel(9, "A", "B", "C", def:"D")
sel(-1, "A", "B", "C", def:"D")

On Jan 4, 2016, at 12:28 PM, Howard Lovatt <howard.lovatt@gmail.com> wrote:

-1 for me. None of it looks or feels like Swift, more like Haskell. I would prefer a library solution for now and remove ?: from the language and add a which into the standard library and see how that goes and if there is need for more.

Sorry,

Howard.

On 5 Jan 2016, at 7:24 AM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org> wrote:

Any feedback on this? I am rethinking the idea of #( because of the # prior usage as a preprocessor directive, but like how it stands out and has a meaning. If no feedback, does it make sense to update my proposal with these ideas? Or does this feel like the wrong direction.

On Dec 30, 2015, at 8:52 AM, Paul Ossenbruggen <possen@gmail.com> wrote:

Some more ideas, this moves away from the notion that we should make it look really close to the ternary but keeps all the benefits of the ternary and improves upon it. Since I have been suggesting a breaking change, it is a good time to rethink it a bit. With this idea a horizontal line (double-dash) separates the control value from the choices, the vertical line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works here, where you can think of it as a numerical index. The advantage of this is, it stands out better and leaves ? for optionals only. This works well with the list form. In the enum case the index is the enum key. I can see that this however may be a problem because # is used for preprocessor like directives. I am suggesting though just the #( sequence is treated differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !( which could be read as "match stick” paren, where the word “match” matches a case, I am pretty sure that would not be considered any better than ?( because it is used for optionals. Another is “witch hat paren” ^( which can be read as “which”. This might create a parse problem with "power of" though, which maybe using ^[ (hat square bracket) could resolve that but not sure if that would create other problems. Some other choices would be &( and @( but did not choose them because they don’t have meaning to me but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF | 0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF
              > 0xFFFFFF) // enum multiline, default: can be used here if preferred.
let fe = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF) // if all cases handled, the last bar is optional

This visually kind of represents what is going on. Horizontal-line directs eye to one of the normal choices. Vertical-line says none found stop looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places where a ternary could be used. So it needs to work on a single line (and multiline) and needs to be compact. By having a compact, “else" that is possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary does.
• The horizontal line serves to provide a place to align the choices to pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or “default” choice, the colon does that in ternary but the bar stands out more.
• The parens group the expression, in a way that the ternary does not. With a ternary it is not until you get to the question mark and the barely visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a ternary.
• #( clearly show beginning and end of the construct so that it is immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with vertical bar like ternary but more visible. This also differs from the switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned as a problem in previous designs.
• All data types for the control are handled the same way, like ternary but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples). Which ternary does not.
• The vast majority of switch statements, at least that I typically use, could be done with this and be much more compact and concise. However if your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch statements used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement assigning an expression result.
• It makes it clear that the result of the expression can be a “let” where less experienced users may think a “var" is required in a switch statement.
• The name binding and assignment occurs in one step unlike the switch statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for multiline and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals only in single expressions for each case. There can only be one expression that gets selected by the control input. This simplifies things compared to a switch statement there are not multiple statements to list afterwards and it does not need the word “case" before each part of the choice to separate each list of statements. This makes it so that it can be much more compact and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
             .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010
     .Red: 0xFF0000
     .Green: 0x00FF00
     .Blue: 0x0000FF
     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I don’t think it is necessary: To make this kind of formatting easy, the editor should help align with the dashes. To allow more space on each line this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF
> 0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com> wrote:

Been thinking about the boolean case a bit more, and how to make it better than a ternary using my proposed syntax. So else could be put there to help show it is the opposite. The downside is this makes it mix keywords and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)
alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.
or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)
Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

_______________________________________________
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

For all the proposals I've seen on this topic, I have to say -1.

While I agree with the notions surrounding this operator, I've yet to see a better alternative presented, and none that feel truly Swift.

If someone has a great proposal, though, I look forward to seeing it.

- Rod

···

On 5 Jan 2016, at 7:28 AM, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

-1 for me. None of it looks or feels like Swift, more like Haskell. I would prefer a library solution for now and remove ?: from the language and add a which into the standard library and see how that goes and if there is need for more.

Sorry,

Howard.

On 5 Jan 2016, at 7:24 AM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org> wrote:

Any feedback on this? I am rethinking the idea of #( because of the # prior usage as a preprocessor directive, but like how it stands out and has a meaning. If no feedback, does it make sense to update my proposal with these ideas? Or does this feel like the wrong direction.

On Dec 30, 2015, at 8:52 AM, Paul Ossenbruggen <possen@gmail.com> wrote:

Some more ideas, this moves away from the notion that we should make it look really close to the ternary but keeps all the benefits of the ternary and improves upon it. Since I have been suggesting a breaking change, it is a good time to rethink it a bit. With this idea a horizontal line (double-dash) separates the control value from the choices, the vertical line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works here, where you can think of it as a numerical index. The advantage of this is, it stands out better and leaves ? for optionals only. This works well with the list form. In the enum case the index is the enum key. I can see that this however may be a problem because # is used for preprocessor like directives. I am suggesting though just the #( sequence is treated differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !( which could be read as "match stick” paren, where the word “match” matches a case, I am pretty sure that would not be considered any better than ?( because it is used for optionals. Another is “witch hat paren” ^( which can be read as “which”. This might create a parse problem with "power of" though, which maybe using ^[ (hat square bracket) could resolve that but not sure if that would create other problems. Some other choices would be &( and @( but did not choose them because they don’t have meaning to me but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF | 0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF
              > 0xFFFFFF) // enum multiline, default: can be used here if preferred.
let fe = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF) // if all cases handled, the last bar is optional

This visually kind of represents what is going on. Horizontal-line directs eye to one of the normal choices. Vertical-line says none found stop looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places where a ternary could be used. So it needs to work on a single line (and multiline) and needs to be compact. By having a compact, “else" that is possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary does.
• The horizontal line serves to provide a place to align the choices to pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or “default” choice, the colon does that in ternary but the bar stands out more.
• The parens group the expression, in a way that the ternary does not. With a ternary it is not until you get to the question mark and the barely visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a ternary.
• #( clearly show beginning and end of the construct so that it is immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with vertical bar like ternary but more visible. This also differs from the switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned as a problem in previous designs.
• All data types for the control are handled the same way, like ternary but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples). Which ternary does not.
• The vast majority of switch statements, at least that I typically use, could be done with this and be much more compact and concise. However if your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch statements used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement assigning an expression result.
• It makes it clear that the result of the expression can be a “let” where less experienced users may think a “var" is required in a switch statement.
• The name binding and assignment occurs in one step unlike the switch statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for multiline and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals only in single expressions for each case. There can only be one expression that gets selected by the control input. This simplifies things compared to a switch statement there are not multiple statements to list afterwards and it does not need the word “case" before each part of the choice to separate each list of statements. This makes it so that it can be much more compact and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
             .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010
     .Red: 0xFF0000
     .Green: 0x00FF00
     .Blue: 0x0000FF
     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I don’t think it is necessary: To make this kind of formatting easy, the editor should help align with the dashes. To allow more space on each line this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF
> 0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com> wrote:

Been thinking about the boolean case a bit more, and how to make it better than a ternary using my proposed syntax. So else could be put there to help show it is the opposite. The downside is this makes it mix keywords and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)
alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.
or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)
Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

_______________________________________________
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

Good feedback, I am all for making it feel more like swift. Any ideas would be welcome. I will also try to come up with some myself.

···

On Jan 4, 2016, at 12:34 PM, Rod Brown <rodney.brown6@icloud.com> wrote:

For all the proposals I've seen on this topic, I have to say -1.

While I agree with the notions surrounding this operator, I've yet to see a better alternative presented, and none that feel truly Swift.

If someone has a great proposal, though, I look forward to seeing it.

- Rod

On 5 Jan 2016, at 7:28 AM, Howard Lovatt via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-1 for me. None of it looks or feels like Swift, more like Haskell. I would prefer a library solution for now and remove ?: from the language and add a which into the standard library and see how that goes and if there is need for more.

Sorry,

Howard.

On 5 Jan 2016, at 7:24 AM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Any feedback on this? I am rethinking the idea of #( because of the # prior usage as a preprocessor directive, but like how it stands out and has a meaning. If no feedback, does it make sense to update my proposal with these ideas? Or does this feel like the wrong direction.

On Dec 30, 2015, at 8:52 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Some more ideas, this moves away from the notion that we should make it look really close to the ternary but keeps all the benefits of the ternary and improves upon it. Since I have been suggesting a breaking change, it is a good time to rethink it a bit. With this idea a horizontal line (double-dash) separates the control value from the choices, the vertical line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works here, where you can think of it as a numerical index. The advantage of this is, it stands out better and leaves ? for optionals only. This works well with the list form. In the enum case the index is the enum key. I can see that this however may be a problem because # is used for preprocessor like directives. I am suggesting though just the #( sequence is treated differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !( which could be read as "match stick” paren, where the word “match” matches a case, I am pretty sure that would not be considered any better than ?( because it is used for optionals. Another is “witch hat paren” ^( which can be read as “which”. This might create a parse problem with "power of" though, which maybe using ^[ (hat square bracket) could resolve that but not sure if that would create other problems. Some other choices would be &( and @( but did not choose them because they don’t have meaning to me but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF | 0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF
              > 0xFFFFFF) // enum multiline, default: can be used here if preferred.
let fe = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF) // if all cases handled, the last bar is optional

This visually kind of represents what is going on. Horizontal-line directs eye to one of the normal choices. Vertical-line says none found stop looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places where a ternary could be used. So it needs to work on a single line (and multiline) and needs to be compact. By having a compact, “else" that is possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary does.
• The horizontal line serves to provide a place to align the choices to pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or “default” choice, the colon does that in ternary but the bar stands out more.
• The parens group the expression, in a way that the ternary does not. With a ternary it is not until you get to the question mark and the barely visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a ternary.
• #( clearly show beginning and end of the construct so that it is immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with vertical bar like ternary but more visible. This also differs from the switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned as a problem in previous designs.
• All data types for the control are handled the same way, like ternary but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples). Which ternary does not.
• The vast majority of switch statements, at least that I typically use, could be done with this and be much more compact and concise. However if your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch statements used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement assigning an expression result.
• It makes it clear that the result of the expression can be a “let” where less experienced users may think a “var" is required in a switch statement.
• The name binding and assignment occurs in one step unlike the switch statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for multiline and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals only in single expressions for each case. There can only be one expression that gets selected by the control input. This simplifies things compared to a switch statement there are not multiple statements to list afterwards and it does not need the word “case" before each part of the choice to separate each list of statements. This makes it so that it can be much more compact and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
             .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010
     .Red: 0xFF0000
     .Green: 0x00FF00
     .Blue: 0x0000FF
     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I don’t think it is necessary: To make this kind of formatting easy, the editor should help align with the dashes. To allow more space on each line this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF
> 0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Been thinking about the boolean case a bit more, and how to make it better than a ternary using my proposed syntax. So else could be put there to help show it is the opposite. The downside is this makes it mix keywords and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)
alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.
or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)
Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com <mailto:charles@charlesism.com>> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

_______________________________________________
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

Our ternary-like switch is now in the "commonly_proposed.md" file, which
doesn't bode very well. It puzzles me that there isn't more enthusiasm. Are
we the only ones who get irritated taking up so much space with a "switch"
when all we need to do is transform between two sets of values?

I think we need to revamp the proposal somehow to make the idea clearer,
because it ought to be pretty compelling.

• Does anyone here have better "side by side" examples of code
before/after?

• Can anyone think of a way to revise the (English) language of the
proposal to make it shorter and sweeter?

Apologies for prescribing instead of doing. My only excuse is that I'm "too
busy"

···

On Mon, Jan 4, 2016 at 3:03 PM, Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

On Jan 4, 2016, at 2:37 PM, Paul Ossenbruggen via swift-evolution < > swift-evolution@swift.org> wrote:

Good feedback, I am all for making it feel more like swift. Any ideas
would be welcome. I will also try to come up with some myself.

My suggestion is to leave ternary alone and try to come up with a
ternary-like switch expression that is workable. I think that is likely
the best change possible at this point.

On Jan 4, 2016, at 12:34 PM, Rod Brown <rodney.brown6@icloud.com> wrote:

For all the proposals I've seen on this topic, I have to say -1.

While I agree with the notions surrounding this operator, I've yet to see
a better alternative presented, and none that feel truly Swift.

If someone has a great proposal, though, I look forward to seeing it.

- Rod

On 5 Jan 2016, at 7:28 AM, Howard Lovatt via swift-evolution < > swift-evolution@swift.org> wrote:

-1 for me. None of it looks or feels like Swift, more like Haskell. I
would prefer a library solution for now and remove ?: from the language and
add a which into the standard library and see how that goes and if there is
need for more.

Sorry,

Howard.

On 5 Jan 2016, at 7:24 AM, Paul Ossenbruggen via swift-evolution < > swift-evolution@swift.org> wrote:

Any feedback on this? I am rethinking the idea of #( because of the #
prior usage as a preprocessor directive, but like how it stands out and has
a meaning. If no feedback, does it make sense to update my proposal with
these ideas? Or does this feel like the wrong direction.

On Dec 30, 2015, at 8:52 AM, Paul Ossenbruggen <possen@gmail.com> wrote:

Some more ideas, this moves away from the notion that we should make it
look really close to the ternary but keeps all the benefits of the ternary
and improves upon it. Since I have been suggesting a breaking change, it is
a good time to rethink it a bit. With this idea a horizontal line
(double-dash) separates the control value from the choices, the vertical
line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works
here, where you can think of it as a numerical index. The advantage of this
is, it stands out better and leaves ? for optionals only. This works well
with the list form. In the enum case the index is the enum key. I can see
that this however may be a problem because # is used for preprocessor like
directives. I am suggesting though just the #( sequence is treated
differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !( which
could be read as "match stick” paren, where the word “match” matches a
case, I am pretty sure that would not be considered any better than ?(
because it is used for optionals. Another is “witch hat paren” ^( which can
be read as “which”. This might create a parse problem with "power of"
though, which maybe using ^[ (hat square bracket) could resolve that but
not sure if that would create other problems. Some other choices would be
&( and @( but did not choose them because they don’t have meaning to me
but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list
form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF |
0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
              .Green: 0x00FF00,
      .Blue: 0x0000FF
             > 0xFFFFFF) // enum multiline, default: can be used here if
preferred.
let fe = #(color -- .Red: 0xFF0000,
              .Green: 0x00FF00,
      .Blue: 0x0000FF) // if all cases handled, the last bar is optional

This visually kind of represents what is going on. Horizontal-line directs
eye to one of the normal choices. Vertical-line says none found stop
looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places
where a ternary could be used. So it needs to work on a single line (and
multiline) and needs to be compact. By having a compact, “else" that is
possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary
does.
• The horizontal line serves to provide a place to align the choices to
pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or
“default” choice, the colon does that in ternary but the bar stands out
more.
• The parens group the expression, in a way that the ternary does not.
With a ternary it is not until you get to the question mark and the barely
visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a
ternary.
• #( clearly show beginning and end of the construct so that it is
immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can
but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with
vertical bar like ternary but more visible. This also differs from the
switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned
as a problem in previous designs.
• All data types for the control are handled the same way, like ternary
but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of
like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples).
Which ternary does not.
• The vast majority of switch statements, at least that I typically use,
could be done with this and be much more compact and concise. However if
your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch statements
used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement
assigning an expression result.
• It makes it clear that the result of the expression can be a “let” where
less experienced users may think a “var" is required in a switch statement.
• The name binding and assignment occurs in one step unlike the switch
statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will
enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for multiline
and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary
does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals
only in single expressions for each case. There can only be one expression
that gets selected by the control input. This simplifies things compared to
a switch statement there are not multiple statements to list afterwards and
it does not need the word “case" before each part of the choice to separate
each list of statements. This makes it so that it can be much more compact
and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new
expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
          .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it
makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010

     .Red: 0xFF0000

     .Green: 0x00FF00

     .Blue: 0x0000FF

     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I
don’t think it is necessary: To make this kind of formatting easy, the
editor should help align with the dashes. To allow more space on each line
this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF
> 0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com> wrote:

Been thinking about the boolean case a bit more, and how to make it better
than a ternary using my proposed syntax. So else could be put there to help
show it is the opposite. The downside is this makes it mix keywords and
operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)

alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.

or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)

Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution < > swift-evolution@swift.org> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com> a
écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color>
(because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution < > swift-evolution@swift.org> wrote:

I like the gist of it too, though you seem to introduce both a new keyword
and a new syntax. (To be clear, I like the syntax but I'm ambivalent
towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes;
that either the comma or the the question mark is redundant in their
current position (you need a start delimiter or an end delimiter but you
don't need both); and that it needs a way to handle a default case if
enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ??
0x000000

Thinking out loud, once you remove the question marks it really looks like
a dictionary literal, so maybe it could even use square brackets to close
the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ??
0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this
is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com> a
écrit :

Just goofing on this a little. What if we called it a "which" statement,
instead of a "switch" statement? It's a bit cutesy, but not too verbose,
and it makes sense if you read it aloud.

let i = which color {
? .Red: 0xFF0000,
? .Green: 0x00FF00,
? .Blue: 0x00000FF
}

let i = which boo {
? true: 1,
? false: 0,
? nil: -1
}

_______________________________________________
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

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

I can work on making the proposal shorter if that will help. Any suggestions, for what could be made better. I am trying to be detailed but maybe that is making it too long.

I am also not sure why this is not getting people excited. This seems like a clear win to me just being able to use auto type inference when initializing it compared to switch statements is huge. I feel like I have tried to address most of the objections and what I am suggesting is quite a bit better than ternary, but with any solution there will be something that involves a trade off, these are problems with ternary as well.

• terse but hard to understand.
• more descriptive but longer.

These are conflicting problems and you can’t solve both but there is nothing so magical about the ternary that I can see. The problems I see with ternary:

• hard to see beginning and end **
• not immediately obvious what it does
• can’t be searched on the web **
• only supports boolean and can’t support more than two outcomes. **
• does not support switch like capabilities **

Good aspects of ternary:
• Terse **
• Fits in small places can be formatted multiline or single line. **
• guarantees the return type is compatible. **
• it is well known by C like language users
• it does not interrupt the control flow like an if statement does. So the code is linear. **
• you are guaranteed a result. **
• Automatically will infer type when binding a name. **
• reduces duplicated code. **
• quick conversions are possible. **

All the items with ** stars next to them are addressed with the proposal others are no worse than ternary.

And it adds some things:
• Adds switch expressions
• Adds using a zero based index to execute an expression.
• Lets you easily see begin and end of the expression
• Different but better
• Supports more than two outcomes.

Downsides:
• breaking change (I think there is value in a unified approach to doing expressions like this, we could leave ternary alone and adapt the rest of the proposal though, this has the downside that there are two ways of doing booleans though).
• not as immediately as familiar as ternary (but similar enough that anyone who knows about ternary will quickly adapt).

···

On Jan 4, 2016, at 3:45 PM, Charles Constant <charles@charlesism.com> wrote:

Our ternary-like switch is now in the "commonly_proposed.md <http://commonly_proposed.md/>" file, which doesn't bode very well. It puzzles me that there isn't more enthusiasm. Are we the only ones who get irritated taking up so much space with a "switch" when all we need to do is transform between two sets of values?

I think we need to revamp the proposal somehow to make the idea clearer, because it ought to be pretty compelling.

• Does anyone here have better "side by side" examples of code before/after?

• Can anyone think of a way to revise the (English) language of the proposal to make it shorter and sweeter?

Apologies for prescribing instead of doing. My only excuse is that I'm "too busy"

On Mon, Jan 4, 2016 at 3:03 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 4, 2016, at 2:37 PM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Good feedback, I am all for making it feel more like swift. Any ideas would be welcome. I will also try to come up with some myself.

My suggestion is to leave ternary alone and try to come up with a ternary-like switch expression that is workable. I think that is likely the best change possible at this point.

On Jan 4, 2016, at 12:34 PM, Rod Brown <rodney.brown6@icloud.com <mailto:rodney.brown6@icloud.com>> wrote:

For all the proposals I've seen on this topic, I have to say -1.

While I agree with the notions surrounding this operator, I've yet to see a better alternative presented, and none that feel truly Swift.

If someone has a great proposal, though, I look forward to seeing it.

- Rod

On 5 Jan 2016, at 7:28 AM, Howard Lovatt via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-1 for me. None of it looks or feels like Swift, more like Haskell. I would prefer a library solution for now and remove ?: from the language and add a which into the standard library and see how that goes and if there is need for more.

Sorry,

Howard.

On 5 Jan 2016, at 7:24 AM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Any feedback on this? I am rethinking the idea of #( because of the # prior usage as a preprocessor directive, but like how it stands out and has a meaning. If no feedback, does it make sense to update my proposal with these ideas? Or does this feel like the wrong direction.

On Dec 30, 2015, at 8:52 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Some more ideas, this moves away from the notion that we should make it look really close to the ternary but keeps all the benefits of the ternary and improves upon it. Since I have been suggesting a breaking change, it is a good time to rethink it a bit. With this idea a horizontal line (double-dash) separates the control value from the choices, the vertical line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works here, where you can think of it as a numerical index. The advantage of this is, it stands out better and leaves ? for optionals only. This works well with the list form. In the enum case the index is the enum key. I can see that this however may be a problem because # is used for preprocessor like directives. I am suggesting though just the #( sequence is treated differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !( which could be read as "match stick” paren, where the word “match” matches a case, I am pretty sure that would not be considered any better than ?( because it is used for optionals. Another is “witch hat paren” ^( which can be read as “which”. This might create a parse problem with "power of" though, which maybe using ^[ (hat square bracket) could resolve that but not sure if that would create other problems. Some other choices would be &( and @( but did not choose them because they don’t have meaning to me but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF | 0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF
              > 0xFFFFFF) // enum multiline, default: can be used here if preferred.
let fe = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF) // if all cases handled, the last bar is optional

This visually kind of represents what is going on. Horizontal-line directs eye to one of the normal choices. Vertical-line says none found stop looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places where a ternary could be used. So it needs to work on a single line (and multiline) and needs to be compact. By having a compact, “else" that is possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary does.
• The horizontal line serves to provide a place to align the choices to pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or “default” choice, the colon does that in ternary but the bar stands out more.
• The parens group the expression, in a way that the ternary does not. With a ternary it is not until you get to the question mark and the barely visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a ternary.
• #( clearly show beginning and end of the construct so that it is immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with vertical bar like ternary but more visible. This also differs from the switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned as a problem in previous designs.
• All data types for the control are handled the same way, like ternary but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples). Which ternary does not.
• The vast majority of switch statements, at least that I typically use, could be done with this and be much more compact and concise. However if your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch statements used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement assigning an expression result.
• It makes it clear that the result of the expression can be a “let” where less experienced users may think a “var" is required in a switch statement.
• The name binding and assignment occurs in one step unlike the switch statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for multiline and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals only in single expressions for each case. There can only be one expression that gets selected by the control input. This simplifies things compared to a switch statement there are not multiple statements to list afterwards and it does not need the word “case" before each part of the choice to separate each list of statements. This makes it so that it can be much more compact and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
             .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010
     .Red: 0xFF0000
     .Green: 0x00FF00
     .Blue: 0x0000FF
     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I don’t think it is necessary: To make this kind of formatting easy, the editor should help align with the dashes. To allow more space on each line this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF
> 0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Been thinking about the boolean case a bit more, and how to make it better than a ternary using my proposed syntax. So else could be put there to help show it is the opposite. The downside is this makes it mix keywords and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)
alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.
or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)
Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com <mailto:charles@charlesism.com>> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

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

Good feedback, I am all for making it feel more like swift. Any ideas would be welcome. I will also try to come up with some myself.

My suggestion is to leave ternary alone and try to come up with a ternary-like switch expression that is workable. I think that is likely the best change possible at this point.

···

On Jan 4, 2016, at 2:37 PM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 4, 2016, at 12:34 PM, Rod Brown <rodney.brown6@icloud.com <mailto:rodney.brown6@icloud.com>> wrote:

For all the proposals I've seen on this topic, I have to say -1.

While I agree with the notions surrounding this operator, I've yet to see a better alternative presented, and none that feel truly Swift.

If someone has a great proposal, though, I look forward to seeing it.

- Rod

On 5 Jan 2016, at 7:28 AM, Howard Lovatt via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-1 for me. None of it looks or feels like Swift, more like Haskell. I would prefer a library solution for now and remove ?: from the language and add a which into the standard library and see how that goes and if there is need for more.

Sorry,

Howard.

On 5 Jan 2016, at 7:24 AM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Any feedback on this? I am rethinking the idea of #( because of the # prior usage as a preprocessor directive, but like how it stands out and has a meaning. If no feedback, does it make sense to update my proposal with these ideas? Or does this feel like the wrong direction.

On Dec 30, 2015, at 8:52 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Some more ideas, this moves away from the notion that we should make it look really close to the ternary but keeps all the benefits of the ternary and improves upon it. Since I have been suggesting a breaking change, it is a good time to rethink it a bit. With this idea a horizontal line (double-dash) separates the control value from the choices, the vertical line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works here, where you can think of it as a numerical index. The advantage of this is, it stands out better and leaves ? for optionals only. This works well with the list form. In the enum case the index is the enum key. I can see that this however may be a problem because # is used for preprocessor like directives. I am suggesting though just the #( sequence is treated differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !( which could be read as "match stick” paren, where the word “match” matches a case, I am pretty sure that would not be considered any better than ?( because it is used for optionals. Another is “witch hat paren” ^( which can be read as “which”. This might create a parse problem with "power of" though, which maybe using ^[ (hat square bracket) could resolve that but not sure if that would create other problems. Some other choices would be &( and @( but did not choose them because they don’t have meaning to me but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF | 0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF
              > 0xFFFFFF) // enum multiline, default: can be used here if preferred.
let fe = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF) // if all cases handled, the last bar is optional

This visually kind of represents what is going on. Horizontal-line directs eye to one of the normal choices. Vertical-line says none found stop looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places where a ternary could be used. So it needs to work on a single line (and multiline) and needs to be compact. By having a compact, “else" that is possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary does.
• The horizontal line serves to provide a place to align the choices to pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or “default” choice, the colon does that in ternary but the bar stands out more.
• The parens group the expression, in a way that the ternary does not. With a ternary it is not until you get to the question mark and the barely visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a ternary.
• #( clearly show beginning and end of the construct so that it is immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with vertical bar like ternary but more visible. This also differs from the switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned as a problem in previous designs.
• All data types for the control are handled the same way, like ternary but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples). Which ternary does not.
• The vast majority of switch statements, at least that I typically use, could be done with this and be much more compact and concise. However if your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch statements used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement assigning an expression result.
• It makes it clear that the result of the expression can be a “let” where less experienced users may think a “var" is required in a switch statement.
• The name binding and assignment occurs in one step unlike the switch statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for multiline and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals only in single expressions for each case. There can only be one expression that gets selected by the control input. This simplifies things compared to a switch statement there are not multiple statements to list afterwards and it does not need the word “case" before each part of the choice to separate each list of statements. This makes it so that it can be much more compact and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
             .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010
     .Red: 0xFF0000
     .Green: 0x00FF00
     .Blue: 0x0000FF
     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I don’t think it is necessary: To make this kind of formatting easy, the editor should help align with the dashes. To allow more space on each line this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF
> 0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Been thinking about the boolean case a bit more, and how to make it better than a ternary using my proposed syntax. So else could be put there to help show it is the opposite. The downside is this makes it mix keywords and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)
alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.
or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)
Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com <mailto:charles@charlesism.com>> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

_______________________________________________
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 <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Our ternary-like switch is now in the "commonly_proposed.md" file, which doesn't bode very well. It puzzles me that there isn't more enthusiasm. Are we the only ones who get irritated taking up so much space with a "switch" when all we need to do is transform between two sets of values?

The ternary-like switch expression is not on the list. Changing or removing ternary itself as well as turning if / else and switch into expressions are on the list.

I think some potential issues with ternary-like switch may have come up but maybe they can be resolved. If not, I don't think we will see progress in this area in the near future.

···

Sent from my iPad

On Jan 4, 2016, at 5:45 PM, Charles Constant <charles@charlesism.com> wrote:

I think we need to revamp the proposal somehow to make the idea clearer, because it ought to be pretty compelling.

• Does anyone here have better "side by side" examples of code before/after?

• Can anyone think of a way to revise the (English) language of the proposal to make it shorter and sweeter?

Apologies for prescribing instead of doing. My only excuse is that I'm "too busy"

On Mon, Jan 4, 2016 at 3:03 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 4, 2016, at 2:37 PM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org> wrote:

Good feedback, I am all for making it feel more like swift. Any ideas would be welcome. I will also try to come up with some myself.

My suggestion is to leave ternary alone and try to come up with a ternary-like switch expression that is workable. I think that is likely the best change possible at this point.

On Jan 4, 2016, at 12:34 PM, Rod Brown <rodney.brown6@icloud.com> wrote:

For all the proposals I've seen on this topic, I have to say -1.

While I agree with the notions surrounding this operator, I've yet to see a better alternative presented, and none that feel truly Swift.

If someone has a great proposal, though, I look forward to seeing it.

- Rod

On 5 Jan 2016, at 7:28 AM, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

-1 for me. None of it looks or feels like Swift, more like Haskell. I would prefer a library solution for now and remove ?: from the language and add a which into the standard library and see how that goes and if there is need for more.

Sorry,

Howard.

On 5 Jan 2016, at 7:24 AM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org> wrote:

Any feedback on this? I am rethinking the idea of #( because of the # prior usage as a preprocessor directive, but like how it stands out and has a meaning. If no feedback, does it make sense to update my proposal with these ideas? Or does this feel like the wrong direction.

On Dec 30, 2015, at 8:52 AM, Paul Ossenbruggen <possen@gmail.com> wrote:

Some more ideas, this moves away from the notion that we should make it look really close to the ternary but keeps all the benefits of the ternary and improves upon it. Since I have been suggesting a breaking change, it is a good time to rethink it a bit. With this idea a horizontal line (double-dash) separates the control value from the choices, the vertical line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works here, where you can think of it as a numerical index. The advantage of this is, it stands out better and leaves ? for optionals only. This works well with the list form. In the enum case the index is the enum key. I can see that this however may be a problem because # is used for preprocessor like directives. I am suggesting though just the #( sequence is treated differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !( which could be read as "match stick” paren, where the word “match” matches a case, I am pretty sure that would not be considered any better than ?( because it is used for optionals. Another is “witch hat paren” ^( which can be read as “which”. This might create a parse problem with "power of" though, which maybe using ^[ (hat square bracket) could resolve that but not sure if that would create other problems. Some other choices would be &( and @( but did not choose them because they don’t have meaning to me but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF | 0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF
              > 0xFFFFFF) // enum multiline, default: can be used here if preferred.
let fe = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF) // if all cases handled, the last bar is optional

This visually kind of represents what is going on. Horizontal-line directs eye to one of the normal choices. Vertical-line says none found stop looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places where a ternary could be used. So it needs to work on a single line (and multiline) and needs to be compact. By having a compact, “else" that is possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary does.
• The horizontal line serves to provide a place to align the choices to pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or “default” choice, the colon does that in ternary but the bar stands out more.
• The parens group the expression, in a way that the ternary does not. With a ternary it is not until you get to the question mark and the barely visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a ternary.
• #( clearly show beginning and end of the construct so that it is immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with vertical bar like ternary but more visible. This also differs from the switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned as a problem in previous designs.
• All data types for the control are handled the same way, like ternary but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples). Which ternary does not.
• The vast majority of switch statements, at least that I typically use, could be done with this and be much more compact and concise. However if your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch statements used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement assigning an expression result.
• It makes it clear that the result of the expression can be a “let” where less experienced users may think a “var" is required in a switch statement.
• The name binding and assignment occurs in one step unlike the switch statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for multiline and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals only in single expressions for each case. There can only be one expression that gets selected by the control input. This simplifies things compared to a switch statement there are not multiple statements to list afterwards and it does not need the word “case" before each part of the choice to separate each list of statements. This makes it so that it can be much more compact and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
             .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010
     .Red: 0xFF0000
     .Green: 0x00FF00
     .Blue: 0x0000FF
     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I don’t think it is necessary: To make this kind of formatting easy, the editor should help align with the dashes. To allow more space on each line this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF
> 0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com> wrote:

Been thinking about the boolean case a bit more, and how to make it better than a ternary using my proposed syntax. So else could be put there to help show it is the opposite. The downside is this makes it mix keywords and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)
alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.
or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)
Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

_______________________________________________
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

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

This is what is on the Commonly Rejected Changes section:
Replace ?: Ternary Operator <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/002609.html&gt;: Definitely magical, but it serves a very important use-case for terse selection of different values. Proposals for alternatives have been intensely discussed, but none have been "better enough" for it to make sense to diverge from the precedent established by the C family of languages.

if/else and switch as expressions <https://lists.swift.org/pipermail/swift-evolution/2015-December/000393.html&gt;: These are conceptually interesting things to support, but many of the problems solved by making these into expressions are already solved in Swift in other ways. Making them expressions introduces significant tradeoffs, and on balance, we haven't found a design that is clearly better than what we have so far.

Please detail what the trade offs are in making them expressions. What are the other ways that Swift currently supports this?

- Paul

···

On Jan 4, 2016, at 4:42 PM, Paul Ossenbruggen <possen@gmail.com> wrote:

I can work on making the proposal shorter if that will help. Any suggestions, for what could be made better. I am trying to be detailed but maybe that is making it too long.

I am also not sure why this is not getting people excited. This seems like a clear win to me just being able to use auto type inference when initializing it compared to switch statements is huge. I feel like I have tried to address most of the objections and what I am suggesting is quite a bit better than ternary, but with any solution there will be something that involves a trade off, these are problems with ternary as well.

• terse but hard to understand.
• more descriptive but longer.

These are conflicting problems and you can’t solve both but there is nothing so magical about the ternary that I can see. The problems I see with ternary:

• hard to see beginning and end **
• not immediately obvious what it does
• can’t be searched on the web **
• only supports boolean and can’t support more than two outcomes. **
• does not support switch like capabilities **

Good aspects of ternary:
• Terse **
• Fits in small places can be formatted multiline or single line. **
• guarantees the return type is compatible. **
• it is well known by C like language users
• it does not interrupt the control flow like an if statement does. So the code is linear. **
• you are guaranteed a result. **
• Automatically will infer type when binding a name. **
• reduces duplicated code. **
• quick conversions are possible. **

All the items with ** stars next to them are addressed with the proposal others are no worse than ternary.

And it adds some things:
• Adds switch expressions
• Adds using a zero based index to execute an expression.
• Lets you easily see begin and end of the expression
• Different but better
• Supports more than two outcomes.

Downsides:
• breaking change (I think there is value in a unified approach to doing expressions like this, we could leave ternary alone and adapt the rest of the proposal though, this has the downside that there are two ways of doing booleans though).
• not as immediately as familiar as ternary (but similar enough that anyone who knows about ternary will quickly adapt).

On Jan 4, 2016, at 3:45 PM, Charles Constant <charles@charlesism.com <mailto:charles@charlesism.com>> wrote:

Our ternary-like switch is now in the "commonly_proposed.md <http://commonly_proposed.md/>" file, which doesn't bode very well. It puzzles me that there isn't more enthusiasm. Are we the only ones who get irritated taking up so much space with a "switch" when all we need to do is transform between two sets of values?

I think we need to revamp the proposal somehow to make the idea clearer, because it ought to be pretty compelling.

• Does anyone here have better "side by side" examples of code before/after?

• Can anyone think of a way to revise the (English) language of the proposal to make it shorter and sweeter?

Apologies for prescribing instead of doing. My only excuse is that I'm "too busy"

On Mon, Jan 4, 2016 at 3:03 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 4, 2016, at 2:37 PM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Good feedback, I am all for making it feel more like swift. Any ideas would be welcome. I will also try to come up with some myself.

My suggestion is to leave ternary alone and try to come up with a ternary-like switch expression that is workable. I think that is likely the best change possible at this point.

On Jan 4, 2016, at 12:34 PM, Rod Brown <rodney.brown6@icloud.com <mailto:rodney.brown6@icloud.com>> wrote:

For all the proposals I've seen on this topic, I have to say -1.

While I agree with the notions surrounding this operator, I've yet to see a better alternative presented, and none that feel truly Swift.

If someone has a great proposal, though, I look forward to seeing it.

- Rod

On 5 Jan 2016, at 7:28 AM, Howard Lovatt via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-1 for me. None of it looks or feels like Swift, more like Haskell. I would prefer a library solution for now and remove ?: from the language and add a which into the standard library and see how that goes and if there is need for more.

Sorry,

Howard.

On 5 Jan 2016, at 7:24 AM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Any feedback on this? I am rethinking the idea of #( because of the # prior usage as a preprocessor directive, but like how it stands out and has a meaning. If no feedback, does it make sense to update my proposal with these ideas? Or does this feel like the wrong direction.

On Dec 30, 2015, at 8:52 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Some more ideas, this moves away from the notion that we should make it look really close to the ternary but keeps all the benefits of the ternary and improves upon it. Since I have been suggesting a breaking change, it is a good time to rethink it a bit. With this idea a horizontal line (double-dash) separates the control value from the choices, the vertical line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works here, where you can think of it as a numerical index. The advantage of this is, it stands out better and leaves ? for optionals only. This works well with the list form. In the enum case the index is the enum key. I can see that this however may be a problem because # is used for preprocessor like directives. I am suggesting though just the #( sequence is treated differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !( which could be read as "match stick” paren, where the word “match” matches a case, I am pretty sure that would not be considered any better than ?( because it is used for optionals. Another is “witch hat paren” ^( which can be read as “which”. This might create a parse problem with "power of" though, which maybe using ^[ (hat square bracket) could resolve that but not sure if that would create other problems. Some other choices would be &( and @( but did not choose them because they don’t have meaning to me but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF | 0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF
              > 0xFFFFFF) // enum multiline, default: can be used here if preferred.
let fe = #(color -- .Red: 0xFF0000,
                .Green: 0x00FF00,
         .Blue: 0x0000FF) // if all cases handled, the last bar is optional

This visually kind of represents what is going on. Horizontal-line directs eye to one of the normal choices. Vertical-line says none found stop looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places where a ternary could be used. So it needs to work on a single line (and multiline) and needs to be compact. By having a compact, “else" that is possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary does.
• The horizontal line serves to provide a place to align the choices to pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or “default” choice, the colon does that in ternary but the bar stands out more.
• The parens group the expression, in a way that the ternary does not. With a ternary it is not until you get to the question mark and the barely visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a ternary.
• #( clearly show beginning and end of the construct so that it is immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with vertical bar like ternary but more visible. This also differs from the switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned as a problem in previous designs.
• All data types for the control are handled the same way, like ternary but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples). Which ternary does not.
• The vast majority of switch statements, at least that I typically use, could be done with this and be much more compact and concise. However if your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch statements used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement assigning an expression result.
• It makes it clear that the result of the expression can be a “let” where less experienced users may think a “var" is required in a switch statement.
• The name binding and assignment occurs in one step unlike the switch statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for multiline and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals only in single expressions for each case. There can only be one expression that gets selected by the control input. This simplifies things compared to a switch statement there are not multiple statements to list afterwards and it does not need the word “case" before each part of the choice to separate each list of statements. This makes it so that it can be much more compact and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
             .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010
     .Red: 0xFF0000
     .Green: 0x00FF00
     .Blue: 0x0000FF
     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I don’t think it is necessary: To make this kind of formatting easy, the editor should help align with the dashes. To allow more space on each line this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF
> 0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com <mailto:possen@gmail.com>> wrote:

Been thinking about the boolean case a bit more, and how to make it better than a ternary using my proposed syntax. So else could be put there to help show it is the opposite. The downside is this makes it mix keywords and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)
alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.
or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)
Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> a écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color> (because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like the gist of it too, though you seem to introduce both a new keyword and a new syntax. (To be clear, I like the syntax but I'm ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes; that either the comma or the the question mark is redundant in their current position (you need a start delimiter or an end delimiter but you don't need both); and that it needs a way to handle a default case if enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff) ?? 0x000000

Thinking out loud, once you remove the question marks it really looks like a dictionary literal, so maybe it could even use square brackets to close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff] ?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com <mailto:charles@charlesism.com>> a écrit :

Just goofing on this a little. What if we called it a "which" statement, instead of a "switch" statement? It's a bit cutesy, but not too verbose, and it makes sense if you read it aloud.

let i = which color {
  ? .Red: 0xFF0000,
  ? .Green: 0x00FF00,
  ? .Blue: 0x00000FF
}

let i = which boo {
  ? true: 1,
  ? false: 0,
  ? nil: -1
}

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

My best guesses here, since I didn't write and don't entirely agree...

*> Please detail what the trade offs are*

Other than more complexity, I think this refers to making the "switch"
statement do two slightly different things. Of course, if we call it
something else, like "match" or "which" then it stops being an issue.

*> What are the other ways that Swift currently supports this?*

As far as I can see, the closest we get are...

    a) The existing "switch" statement, or if else statement (preceded with
a statement to declare the variable. yuck). I think this is verbose enough
to qualify as "confusing"

    b) Creating an anonymous dict, and immediately accessing it (which
means the keys need to be Hashable). This isn't very flexible

    c) Creating a special init or function, to map one enum, to another.
This is also verbose, and not flexible, and moves the code away from where
it used (even if you never reuse the mapping).

    d) Chaining a bunch of conditions in a ternary... Horrible.

Anyone know of any better alternatives? It feels like I'm missing something.

···

On Mon, Jan 4, 2016 at 10:34 PM, Paul Ossenbruggen <possen@gmail.com> wrote:

This is what is on the Commonly Rejected Changes section:

   -

   Replace ?: Ternary Operator
   <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/002609.html&gt;:
   Definitely magical, but it serves a very important use-case for terse
   selection of different values. Proposals for alternatives have been
   intensely discussed, but none have been "better enough" for it to make
   sense to diverge from the precedent established by the C family of
   languages.
   -

   if/else and switch as expressions
   <https://lists.swift.org/pipermail/swift-evolution/2015-December/000393.html&gt;:
   These are conceptually interesting things to support, but many of the
   problems solved by making these into expressions are already solved in
   Swift in other ways. Making them expressions introduces significant
   tradeoffs, and on balance, we haven't found a design that is clearly better
   than what we have so far.

Please detail what the trade offs are in making them expressions. What are
the other ways that Swift currently supports this?

- Paul

On Jan 4, 2016, at 4:42 PM, Paul Ossenbruggen <possen@gmail.com> wrote:

I can work on making the proposal shorter if that will help. Any
suggestions, for what could be made better. I am trying to be detailed but
maybe that is making it too long.

I am also not sure why this is not getting people excited. This seems like
a clear win to me just being able to use auto type inference when
initializing it compared to switch statements is huge. I feel like I have
tried to address most of the objections and what I am suggesting is quite a
bit better than ternary, but with any solution there will be something that
involves a trade off, these are problems with ternary as well.

• terse but hard to understand.
• more descriptive but longer.

These are conflicting problems and you can’t solve both but there is
nothing so magical about the ternary that I can see. The problems I see
with ternary:

• hard to see beginning and end **
• not immediately obvious what it does
• can’t be searched on the web **
• only supports boolean and can’t support more than two outcomes. **
• does not support switch like capabilities **

Good aspects of ternary:
• Terse **
• Fits in small places can be formatted multiline or single line. **
• guarantees the return type is compatible. **
• it is well known by C like language users
• it does not interrupt the control flow like an if statement does. So the
code is linear. **
• you are guaranteed a result. **
• Automatically will infer type when binding a name. **
• reduces duplicated code. **
• quick conversions are possible. **

All the items with ** stars next to them are addressed with the proposal
others are no worse than ternary.

And it adds some things:
• Adds switch expressions
• Adds using a zero based index to execute an expression.
• Lets you easily see begin and end of the expression
• Different but better
• Supports more than two outcomes.

Downsides:
• breaking change (I think there is value in a unified approach to doing
expressions like this, we could leave ternary alone and adapt the rest of
the proposal though, this has the downside that there are two ways of doing
booleans though).
• not as immediately as familiar as ternary (but similar enough that
anyone who knows about ternary will quickly adapt).

On Jan 4, 2016, at 3:45 PM, Charles Constant <charles@charlesism.com> > wrote:

Our ternary-like switch is now in the "commonly_proposed.md" file, which
doesn't bode very well. It puzzles me that there isn't more enthusiasm. Are
we the only ones who get irritated taking up so much space with a "switch"
when all we need to do is transform between two sets of values?

I think we need to revamp the proposal somehow to make the idea clearer,
because it ought to be pretty compelling.

• Does anyone here have better "side by side" examples of code
before/after?

• Can anyone think of a way to revise the (English) language of the
proposal to make it shorter and sweeter?

Apologies for prescribing instead of doing. My only excuse is that I'm
"too busy"

On Mon, Jan 4, 2016 at 3:03 PM, Matthew Johnson via swift-evolution < > swift-evolution@swift.org> wrote:

On Jan 4, 2016, at 2:37 PM, Paul Ossenbruggen via swift-evolution < >> swift-evolution@swift.org> wrote:

Good feedback, I am all for making it feel more like swift. Any ideas
would be welcome. I will also try to come up with some myself.

My suggestion is to leave ternary alone and try to come up with a
ternary-like switch expression that is workable. I think that is likely
the best change possible at this point.

On Jan 4, 2016, at 12:34 PM, Rod Brown <rodney.brown6@icloud.com> wrote:

For all the proposals I've seen on this topic, I have to say -1.

While I agree with the notions surrounding this operator, I've yet to see
a better alternative presented, and none that feel truly Swift.

If someone has a great proposal, though, I look forward to seeing it.

- Rod

On 5 Jan 2016, at 7:28 AM, Howard Lovatt via swift-evolution < >> swift-evolution@swift.org> wrote:

-1 for me. None of it looks or feels like Swift, more like Haskell. I
would prefer a library solution for now and remove ?: from the language and
add a which into the standard library and see how that goes and if there is
need for more.

Sorry,

Howard.

On 5 Jan 2016, at 7:24 AM, Paul Ossenbruggen via swift-evolution < >> swift-evolution@swift.org> wrote:

Any feedback on this? I am rethinking the idea of #( because of the #
prior usage as a preprocessor directive, but like how it stands out and has
a meaning. If no feedback, does it make sense to update my proposal with
these ideas? Or does this feel like the wrong direction.

On Dec 30, 2015, at 8:52 AM, Paul Ossenbruggen <possen@gmail.com> wrote:

Some more ideas, this moves away from the notion that we should make it
look really close to the ternary but keeps all the benefits of the ternary
and improves upon it. Since I have been suggesting a breaking change, it is
a good time to rethink it a bit. With this idea a horizontal line
(double-dash) separates the control value from the choices, the vertical
line (bar) indicates none of the above.

Rather than use the ?( as I have suggested in the past, I think #( works
here, where you can think of it as a numerical index. The advantage of this
is, it stands out better and leaves ? for optionals only. This works well
with the list form. In the enum case the index is the enum key. I can see
that this however may be a problem because # is used for preprocessor like
directives. I am suggesting though just the #( sequence is treated
differently. Or the ?( is fine with me as well.

I have gone through a lot of options, some others I looked at are !(
which could be read as "match stick” paren, where the word “match” matches
a case, I am pretty sure that would not be considered any better than ?(
because it is used for optionals. Another is “witch hat paren” ^( which can
be read as “which”. This might create a parse problem with "power of"
though, which maybe using ^[ (hat square bracket) could resolve that but
not sure if that would create other problems. Some other choices would be
&( and @( but did not choose them because they don’t have meaning to me
but they do have the advantage of standing out like the #(.

let fa = #(truth -- 1 | 0) // boolean case.
let fb = #(pickOne -- "A", "B", "C", "D", "E", "F", "G" | "Z”) // list
form, pick index, zero based.
let fc = #(color -- .Red: 0xFF0000, .Green: 0x00FF00, .Blue: 0x0000FF |
0xFFFFFF) // enum form.
let fd = #(color -- .Red: 0xFF0000,
              .Green: 0x00FF00,
      .Blue: 0x0000FF
             > 0xFFFFFF) // enum multiline, default: can be used here if
preferred.
let fe = #(color -- .Red: 0xFF0000,
              .Green: 0x00FF00,
      .Blue: 0x0000FF) // if all cases handled, the last bar is
optional

This visually kind of represents what is going on. Horizontal-line
directs eye to one of the normal choices. Vertical-line says none found
stop looking and do the otherwise choice. Kind of like a train switch.

The strong feedback was that a replacement has to be usable in places
where a ternary could be used. So it needs to work on a single line (and
multiline) and needs to be compact. By having a compact, “else" that is
possible on a single line.

Comparisons to ternary and other approaches:
• It is very concise like ternary and can fit in places that a ternary
does.
• The horizontal line serves to provide a place to align the choices to
pick from, not as necessary with ternary.
• The vertical line stops the eye and indicates this is the “else” or
“default” choice, the colon does that in ternary but the bar stands out
more.
• The parens group the expression, in a way that the ternary does not.
With a ternary it is not until you get to the question mark and the barely
visible colon that you realize it is a ternary.
• The #( indicates immediately that the expression has started unlike a
ternary.
• #( clearly show beginning and end of the construct so that it is
immediately identifiable unlike ternary.
• Makes quick one line conversions easily achievable just as ternary can
but allowing more than just boolean.
• The “else” choice is always last and is compactly represented with
vertical bar like ternary but more visible. This also differs from the
switch statement form, in that it is much more compact than “default:"
• The dash does not create a double colon for enum case as was mentioned
as a problem in previous designs.
• All data types for the control are handled the same way, like ternary
but now supports more than boolean, it supports any enumerable tope.
• The list form looks like a Array sort of, the enum form looks sort of
like a Dictionary, this should make it seem familiar.
• The enum form also supports pattern matching. (see below for examples).
Which ternary does not.
• The vast majority of switch statements, at least that I typically use,
could be done with this and be much more compact and concise. However if
your needs are more complex, then the switch statement is still available.
• You get the benefits of automatic type inference where switch
statements used to assign an expression result don’t let you.
• It removes a lot of duplicated code compared to a switch statement
assigning an expression result.
• It makes it clear that the result of the expression can be a “let”
where less experienced users may think a “var" is required in a switch
statement.
• The name binding and assignment occurs in one step unlike the switch
statement, when used to assign an expression result.
• It always returns a result of an expression like ternary does and will
enforce that the result is a the same type.
• Like ternary leaves the formatting choice to the developer for
multiline and single-line but easily handles both.
• Searchable with web search unlike ternary.
• Enum uses the same format as the familiar switch syntax which ternary
does not.
• #( stands out more than ?( in my earlier designs.

The difference between this and the switch statement is that this deals
only in single expressions for each case. There can only be one expression
that gets selected by the control input. This simplifies things compared to
a switch statement there are not multiple statements to list afterwards and
it does not need the word “case" before each part of the choice to separate
each list of statements. This makes it so that it can be much more compact
and means the word “case” is not necessary.

Below I go through a bunch of comparisons to statement form, vs new
expression also different formatting options:

let res : Int
switch color {
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
default:
    res = 0xFFFFFF
}

With the new expression:

let res = #(color -- .Red: 0xFF0000
          .Green: 0x00FF00
                     .Blue: 0x0000FF
                     > 0xFFFFFF}

This uses a where clause with existing statement:

let res : Int
switch color {
    case .Red where shade == .Dark: res = 0xFF1010
    case .Red: res = 0xFF0000
    case .Green: res = 0x00FF00
    case .Blue: res = 0x0000FF
    default:
        res = 0xFFFFFF
}

This one way to do the same thing with multiline and the expression if it
makes it clearer, some may prefer this:

let res = #(color --
    case .Red where shade == .Dark: 0xFF1010
    case .Red: 0xFF0000
    case .Green: 0x00FF00
    case .Blue: 0x0000FF
    default: 0xFFFFFF
}

Since this the case does not add anything, you can do this as well:

let res = #(color —- .Red where shade == .Dark: 0xFF1010

     .Red: 0xFF0000

     .Green: 0x00FF00

     .Blue: 0x0000FF

     > 0xFFFFFF}

If “case” makes the “where" clearer then I am fine requiring it but I
don’t think it is necessary: To make this kind of formatting easy, the
editor should help align with the dashes. To allow more space on each line
this would also work:

let res = #(color
    -— .Red where shade == .Dark: 0xFF1010
         .Red: 0xFF0000
         .Green: 0x00FF00
         .Blue: 0x0000FF
         > 0xFFFFFF}

one last option for maximum space on the line:

let res = #(color —-
.Red where shade == .Dark: 0xFF1010
.Red: 0xFF0000
.Green: 0x00FF00
.Blue: 0x0000FF
> 0xFFFFFF}

On Dec 23, 2015, at 11:51 AM, Paul Ossenbruggen <possen@gmail.com> wrote:

Been thinking about the boolean case a bit more, and how to make it
better than a ternary using my proposed syntax. So else could be put there
to help show it is the opposite. The downside is this makes it mix keywords
and operators so seems a bit jarring.

With the new form parenthesis are built into it and are required:

x = ?(x == y : 49 else 3)

alternatively the bang means do the opposite:

x = ?(x == y : 49 ! 3) // not sure this creates a parsing problem.

or if the above causes a parsing problem:

x = ?(x == y : 49 | 3)

Any thoughts?

On Dec 23, 2015, at 7:02 AM, Félix Cloutier via swift-evolution < >> swift-evolution@swift.org> wrote:

I know, but that won't support pattern matching.

Félix

Le 23 déc. 2015 à 02:22:07, David Waite <david@alkaline-solutions.com> a
écrit :

In the case where your input is hashable, you could just do:

let i = [.Red:0xff0000, .Green:0x00ff00, .Blue:0x0000ff][color]

this would mean that color must be a Color and not an Optional<Color>
(because of swift 2.x limitations)

-DW

On Dec 22, 2015, at 8:04 AM, Félix Cloutier via swift-evolution < >> swift-evolution@swift.org> wrote:

I like the gist of it too, though you seem to introduce both a new
keyword and a new syntax. (To be clear, I like the syntax but I'm
ambivalent towards reusing switch instead of which.)

My minor suggestions would to avoid braces for things that aren't scopes;
that either the comma or the the question mark is redundant in their
current position (you need a start delimiter or an end delimiter but you
don't need both); and that it needs a way to handle a default case if
enumeration isn't exhaustive (I'd do that by returning an optional).

let i = which color (.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff)
?? 0x000000

Thinking out loud, once you remove the question marks it really looks
like a dictionary literal, so maybe it could even use square brackets to
close the gap.

let i = which color [.Red: 0xff0000, .Green: 0x00ff00, .Blue: 0x0000ff]
?? 0x000000

I thought about subscripting a dictionary literal in place:

[Color.Red: 0xff0000, ...][color] ?? 0x000000

but that won't support elaborate pattern matching, and I think that this
is a deal breaker for the functional folks.

Félix

Le 22 déc. 2015 à 09:31:32, Charles Constant <charles@charlesism.com> a
écrit :

Just goofing on this a little. What if we called it a "which" statement,
instead of a "switch" statement? It's a bit cutesy, but not too verbose,
and it makes sense if you read it aloud.

let i = which color {
? .Red: 0xFF0000,
? .Green: 0x00FF00,
? .Blue: 0x00000FF
}

let i = which boo {
? true: 1,
? false: 0,
? nil: -1
}

_______________________________________________
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

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

There was a popular pattern which went as follows:

let myThing = {
  if someCondition {
    return 1
  } else {
    return 2
  }
}()

It's a little ugly, but the compiler is apparently smart enough to inline/optimize away the anonymous closure. It became less popular once Swift got support for declaring lets without an initial value.

Austin

···

On Jan 4, 2016, at 10:55 PM, Charles Constant via swift-evolution <swift-evolution@swift.org> wrote:

My best guesses here, since I didn't write and don't entirely agree...

> Please detail what the trade offs are

Other than more complexity, I think this refers to making the "switch" statement do two slightly different things. Of course, if we call it something else, like "match" or "which" then it stops being an issue.

> What are the other ways that Swift currently supports this?

As far as I can see, the closest we get are...

    a) The existing "switch" statement, or if else statement (preceded with a statement to declare the variable. yuck). I think this is verbose enough to qualify as "confusing"

    b) Creating an anonymous dict, and immediately accessing it (which means the keys need to be Hashable). This isn't very flexible

    c) Creating a special init or function, to map one enum, to another. This is also verbose, and not flexible, and moves the code away from where it used (even if you never reuse the mapping).

    d) Chaining a bunch of conditions in a ternary... Horrible.

Anyone know of any better alternatives? It feels like I'm missing something.