[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