[swift-evolution] ternary operator ?: suggestion

Paul Ossenbruggen possen at gmail.com
Sun Dec 6 23:09:33 CST 2015


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


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

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

y is out of scope here so you currently have to write…
 
let y : Int
switch  x  {
	case 1:  y = 5
	case 2:  y = 6
	case 3:  y = 7
	default: y = 8
}
print(y)

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

> On Dec 6, 2015, at 7:45 PM, Alex Lew <alexl.mail+swift at gmail.com> wrote:
> 
> I think the compiler can just assume that if it's valid to have a statement in a given context, the if or switch should be interpreted as a statement.
> 
> A convention of keeping if-expressions to one line, and switch-expressions to one line per case, would make things relatively readable (though I don't feel that strongly about the convention):
> 
> let foo = if condition { function1() } else { function2() }
> let foo = switch color {
>     case .Red: function1()
>     case .Green: function2()
>     default: function3()
> }
> 
> I'm still not totally convinced by Matthew's argument that making the syntax lighter-weight is orthogonal to the expression/statement question. In my mind, it makes sense to have both a heavier switch statement, (which might have many sub-statements in each branch), and also a lighter-weight option for a quick pattern-match inside an expression (like the ones we've been discussing in this thread). 
> 
> This is the whole idea behind the ternary operator in C, and the "a = value if condition else otherValue" in Python, etc. That's why I kind of like the ternary-operator-inspired syntax for pattern matching. It would be awful to use for statements -- just like it would be awful to replace if/else statements in C with the C ternary operator's syntax -- but I think it's pretty readable for expressions. It just seems to fit: just like C's if, while, for, and switch can now pattern match in Swift, so can ?: (not to mention that the colons after each case "rhyme" with the original colon in the ternary operator).
> 
> But I believe I'm in the minority on that opinion, which is totally fine. :)
> 
> I think the questions then become: first, as Chris has asked, do the if/switch expressions provide enough of a benefit (in terms of conciseness) to be worth implementing? And, as Matthew suggested: is there a lighter-weight syntax that would make both statements and expressions more succinct?
> 
> All best,
> Alex
> 
> On Sun, Dec 6, 2015 at 10:11 PM, Paul Ossenbruggen <possen at gmail.com <mailto:possen at gmail.com>> wrote:
> In thinking about this, is there a way to have the compiler detect that something is a statement vs expression? Is it always clear to users when something is an expression vs a statement? In blurring the lines between expressions and statements complications arise anytime there is a return value returned by the result of “switch” or “if” it suddenly becomes an expression. Are there gray areas where it is hard to determine whether it is one vs the other when we use the those keywords? If it is not possible to determine for every situation or confusing to users, then maybe a new keyword for expressions is necessary. When a branch of an else returns void does it then become a statement? We should avoid shoehorning it in just to avoid another keyword. 
> 
> let foo = if condition {
>  x = 1 // implied void -- illegal
> } else {
>  10  // returns expression
> }
> 
> also, I think this is confusing:
> 
> let foo = if condition {
>  function1()
> } else {
>  function2()
> }
> 
> it is not obvious that this is an assignment or that the functions return anything. Earlier I suggested something using =  to make it more clear. This is similar to the requirement that functions that throw are prefixed with with “try"
> 
> let foo if condition {
>  = function1()
> } else {
>  = function2()
> }
> 
> also for the literal case: 
> 
> let foo  if condition {
>  =  1 // can’t accidentally put a non expression here. 
> } else {
>  = 10  // returns expression
> }
> 
> Which makes it clear that it is an expression coming back from both sides of the “if”. The switch case is a little trickier because of the case. 
> 
> let foo switch value {
>  = .Red:   function1()
>  = .Green  function2() 
>  =  default: function3()
> }
> 
> The equal emphasizes the functions return a value for each part of the switch and assigns to “foo”, but somehow is unsatisfying having that equal everywhere. 
> 
> One the other hand,  the ternary operator being an expression this confusion does not exist, it is clear that function1() and function2() must return a value. 
> 
> let foo = condition ? function1() : function2() 
> 
> even when on separate lines:
> 
> let foo = condition ? 
>  function1() :
>  function2() 
> 
> So maybe Alex’s original suggestion works better where the ? operator is extended to support a switch like expression and keeping the two statements and expressions separate. 
> 
> let foo = condition ? 
>  .Red : .Green
>  .Green : Red
> 
> let foo = condition ? 
>  .Red: function1()
>  .Green: function2() 
> 
> let foo = condition ? .Red: function1() .Blue: function2() default:. function3() 
> 
> also could include optional cases:
> 
> let foo = condition ? case .Red: function1(), case .Blue: functions(), default: function3()
> 
> Which brings us back full circle to the keyword because most people don’t like the ? operator which is why Alex suggested “match":
> 
> let foo = match condition 
>  .Red: function1()
>  .Green: function2() 
>  default: function3()
> 
> or with optional cases: 
> 
> let foo = match condition 
>  case .Red: function1()
>  case .Green: function2() 
>  default: function3()
> 
> for booleans :
> 
> let too = match condition function() else function2()
> 
> I still like this better. A new keyword makes sure there is no confusion about expressions vs statements and avoids complications with the return values. Match would always be an expression, if/else/swtich are always statements. Also those keywords don’t change behavior if a user changes a statement into an expression by assigning the expression the else part would suddenly be required. 
> 
> if condition {
>  function1()
> } 
> 
> is changed to 
> 
> let foo = if condition {
>  function1()  
> }  
> 
> is now an error, because there is no else. Now if function1() does not return a value. you have another error just changing it to assign completely changes the behavior of the “if” statement. 
> 
> - Paul
> 
>> On Dec 6, 2015, at 2:11 PM, Paul Ossenbruggen < possen at gmail.com <mailto:possen at gmail.com>> wrote:
>> 
>> so the rule would have to be that the “switch" or “if" must return a value of compatible type. Not sure I love all the braces in the “if" case but it does follow the existing language rules with the exception that it must be have an else.
>> 
>> let thisColor = if condition { .Red }   // illegal for expressions but not statements
>> 
>> Can still do this for statements:
>> if condition {
>>  x = 40
>> } 
>> 
>> likewise:
>> let thisColor = if condition { .Red } else { 21 } // illegal unless thisColor is Any 
>> 
>> unless: 
>> let thisColor : Any = if condition { .Red } else { 21 } // illegal unless thisColor is Any 
>> 
>> It would be nice to omit braces in this expression case but not for statements: 
>> let thisColor = if condition .Red else .Blue 
>> 
>> in statements braces would be required: 
>> 
>> if condition {
>>  x = 32
>> } else {
>>  y = 44
>> }
>> 
>>> >     }
>>> On Dec 6, 2015, at 1:52 PM, Alex Lew via swift-evolution < swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>> I agree that it's simplest to just reuse switch keyword, and keep braces. +1.  
>>> 
>>> Would you allow the same thing with if?
>>> 
>>> let thisColor = if condition { .Red } else { .Blue }
>>> 
>>> On Sun, Dec 6, 2015 at 4:44 PM, Rudolf Adamkovic   <salutis at me.com <mailto:salutis at me.com>>  wrote: 
>>> > On 06 Dec 2015, at 22:35, thorsten--- via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>> >
>>> > I would prefer the expression to match the statement. The only difference would be that all parts that were statements now have to be expressions.
>>> 
>>> +1 
>>> 
>>> >
>>> > Therefore the switch-expression should simply look like follows:
>>> >
>>> > let thisColor = switch thatColor {
>>> >         case .Red: .Green // must be an expression
>>> >         default: .Yellow      // must be an expression
>>> >     }
>>> >
>>> > No returns needed in the case clauses.
>>> 
>>> This actually looks great. One simple rule and zero new keywords. 
>>> 
>>> Readable and simple to learn. 
>>> 
>>> Fantastic! 
>>> 
>>> > Formatting this as a one-liner would just require adding semicolons (though I wouldn't recommend this).
>>> >
>>> > -Thorsten
>>> > _______________________________________________ 
>>> > swift-evolution mailing list 
>>> >   swift-evolution at swift.org <mailto:swift-evolution at swift.org> 
>>> >   https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution> 
>>> 
>>>  _______________________________________________ 
>>> swift-evolution mailing list 
>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org> 
>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151206/9b61e822/attachment.html>


More information about the swift-evolution mailing list