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

Vladimir.S svabox at gmail.com
Sat Sep 3 04:34:44 CDT 2016


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



More information about the swift-evolution mailing list