[swift-evolution] [Pitch]: Require parenthesis for ternary operator '?:' or change its priority

Thorsten Seitz tseitz42 at icloud.com
Sat Sep 3 11:21:14 CDT 2016



> Am 03.09.2016 um 13:55 schrieb David Sweeris <davesweeris at mac.com>:
> 
> I don't he's proposing to change the precedence of "?:" per se, just requiring — as part of its syntax — it to be enclosed in parens when it's not by itself:

Ah, ok, I didn't get that. That makes more sense, then :-)

-Thorsten 


> 
> x = condition ? y : z //ok, since it's by itself
> x = (test || condition) ? y : z //ok, since it's still technically by itself
> x = test || (condition ? y : z) //ok, has parens
> x = test || condition ? y : z //syntax error, no parens
> 
> I don't actually know what the correct precedence for ?: is because I never use that 4th "form", for the very reason this change is being proposed: it's too easy for me to get mixed up otherwise.
> 
> Where was I? Oh, right, as I understand it, this doesn't so much change ?:'s precedence as it does remove it from the precedence "system".
> 
> - Dave Sweeris
> 
> Sent from my iPhone, without sleep.
> 
>> On Sep 3, 2016, at 06:21, Thorsten Seitz via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>> The problem you describe is not the priority of the ternary operator but that developers just assume a priority without checking (or learning) whether their assumption is correct. Changing the priority won't solve that problem, it would only shift the problem over to those developers assuming the other priority. Worse, it would create this problem for those developers knowing the correct priority, because they now have to relearn the new priority with the added difficulty of the priority being different from C.
>> 
>> I'm not sure whether the problem really is one (other operators have priorities too, which have to be learned), but assuming for the moment that it is, a solution would be to replace the ternary operator with an if-expression: if condition then expr1 else expr2
>> This would enclose the condition between two keywords and thereby be free of misunderstandings.
>> Replacing the ternary operator is on the commonly asked changes list, though, and therefore requires new arguments/insights why a replacement would make sense. I think the possibly confusing priority has been discussed already in the past and therefore wouldn't count as new insight, though I'm not quite sure.
>> 
>> -Thorsten 
>> 
>>> Am 03.09.2016 um 11:34 schrieb Vladimir.S via swift-evolution <swift-evolution at swift.org>:
>>> 
>>> (Seems my first email was not resent by mailing list due to its temporary problems. So second attempt)
>>> 
>>> I'm not sure if it is a correct time to discuss this, if not - I'll hold this for later time.
>>> 
>>> I was reading the article of author of some C/C++ static code analyzer tool where he was analyzing and discussing about code of some open source program. And there was a paragraph about bugs people make when using ternary operator. There a lot of bugs in C/C++ sources of well-known open source programs(like Chromium, ReactOS, MongoDB, Unreal Engine 4, Wine, FreeBSD Kernel and many others) made when developer assumes that priority of '?:' operator is higher than other operators like '+', '*', '|', '&' and other.
>>> 
>>> Examples:
>>> 
>>> int edge_height = titlebar_bottom->height() -
>>>    ShouldShowClientEdge() ? kClientEdgeThickness : 0;
>>> 
>>> ULONG treg = 0x54 + (dev < 3) ? (dev << 1) : 7;
>>> 
>>> if (IP_PACKET_SIZE < parsedPacket.info.H263.dataLength +
>>>       parsedPacket.info.H263.insert2byteStartCode ? 2:0) {...}
>>> 
>>> stringstream ss;
>>> ss << (sizeof(char *) == 8) ? " 64bit" : " 32bit";
>>> 
>>> return UniformVectorExpressions.GetAllocatedSize()
>>>      + UniformScalarExpressions.GetAllocatedSize()
>>>      + Uniform2DTextureExpressions.GetAllocatedSize()
>>>      + UniformCubeTextureExpressions.GetAllocatedSize()
>>>      + ParameterCollections.GetAllocatedSize()
>>>      + UniformBufferStruct
>>>          ?
>>>          (sizeof(FUniformBufferStruct) +
>>>           UniformBufferStruct->GetMembers().GetAllocatedSize())
>>>          :
>>>          0;
>>> 
>>> .. and so on..
>>> 
>>> Yes, in Swift we have no problem with mixing lets say Ints and Boolean values. But, it seems that it is highly possible to catch the same kind of problem with ternary operator in Swift for boolean values:
>>> 
>>> func isOne()->Bool { print(1); return false }
>>> func isTwo()->Bool { print(2); return false }
>>> 
>>> let a = true
>>> let b = true
>>> 
>>> let result = a || (b) ? isOne() : isTwo() // prints 1
>>> 
>>> print(result) // false
>>> 
>>> As you understand, to work correctly we need parentheses:
>>> let result = a || ((b) ? isOne() : isTwo()) // <nothing>
>>> print(result) // true
>>> 
>>> ..or set priority of '?:' operator higher than other operators (but this probably could *silently* break old code?)
>>> 
>>> I was trying to play with custom operators and ternary operator :
>>> 
>>> func <<(lhs: inout String, rhs: String) { lhs += rhs }
>>> func <<(lhs: inout String, rhs: Bool) { lhs += rhs.description }
>>> 
>>> let x = 10
>>> var s = ""
>>> 
>>> s << "abc"
>>> print(s) // abc
>>> 
>>> s << (x == 10) ? "10" : "not 10"
>>> print(s)
>>> 
>>> .. but this crashes the compiler(bug reported), but this shows that could be other ways when ternary operator works not as expected by many developers.
>>> 
>>> I believe the problem is worth to be discussed and probably solved for Swift in near future.
>>> 
>>> Opinions?
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160903/9e277e76/attachment.html>


More information about the swift-evolution mailing list