[swift-evolution] [Last second] Precedence of nil-coalescing operator seems too low
svabox at gmail.com
Thu Sep 8 06:21:23 CDT 2016
On 08.09.2016 12:08, Pyry Jahkola via swift-evolution wrote:
> To stay slightly on topic of the original Subject line, I'd point out that
> no one has yet demonstrated an example where the current precedence
> position of `??` causes bugs at runtime.
Why do you need to see some precedence(I can create a sample project for
you on github) while this construction is so simple and obviously would be
used often and *will* cause bugs. I insist that if construction easily
allows logical bugs in it - there will be a lot of bugs in such
construction in different projects/frameworks/modules.
> The original motivation by Erica simply failed to compile without the
> parentheses, so it wasn't about confusion so much as about mere
Sorry, but you are just not right. The code compiles without even warning:
Swift Ver. 3.0 (Sep 6, 2016)
Platform: Linux (x86_64)
let foundIndex : Int? = 1
let lastIndex = 2
let nextIndex = foundIndex ?? lastIndex + 1
print(nextIndex) // 1
> convenience. And there exist actual uses where the current precedence
> brings greater convenience, e.g. when the RHS expression contains
> arithmetic operations.
> Like Wux, I also don't think we have any reason to adjust the precedence of
> `??` from what it is.
After I showed the code compiles, would you change your opinion?
IMO the best solution which will dramatically reduce the number of future
logical errors(bugs) in code with mixed operators would be to
require(probably, just by raising a compilation warning) parenthesis when
operators from different groups are mixed in the same expression. IMO no
need in complex rules to make Swift safer. I.e. when you have a = 10 + 5 *
10 - you don't need parenthesis, when you have a = b << 4 - also all is
ok, but if you have a = b << 4 + 5 * 10 - you'll have a warning until add
parenthesis to make your intention clear. IMO this should prevent almost
all logical errors in such expressions and increase the common quality of
Swift code(in each project/framework/module).
> * * *
> But then, I also think we should do something to our bitwise ops:
>> On 08 Sep 2016, at 09:58, Xiaodi Wu via swift-evolution
>> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> You and I seem to agree that `let i = 4 << 1 + 3` is rather reasonable.
> Here, I would actually differ somewhat. If there's something that ought to
> be higher in precedence than `+` and `*`, IMO that would be actual
> exponentiation, which could be approximated in a math library by the
> presently missing `**` operator, for example.
>> I am not sure how one can make an unintended error either reading or
>> writing this line of code[*].
>> [*] Actually, I can see precisely one way to make such an unintended
>> error, since I have actually done so. It has to do with Swift having
>> moved away from the classical C-family operator precedence table. I would
>> actually not be opposed to making changes that guard against such an error.
> There's a fair amount of C code out in the wild that is going to be
> migrated into Swift in the near future. And that code would benefit if
> Swift's precedence rules didn't unexpectedly break from C – that is, not
> without the programmer's awareness.
> The key differences to C that I think will cause confusion in Swift are:
> A) Unlike C, Swift defines `<<` and `>>` with the highest precedence.
> B) Unlike C, Swift defines `&` at multiplication precedence (`*` etc.).
> C) Unlike C, Swift defines both `^` and `|` at equal precedence to each
> other, and that is the precedence of addition (`+` etc.).
> Other than that, we also use equal precedence for all comparison operators
> but at the same time remove their associativity, so that can't cause
> runtime problems (as such code would fail to compile). Here's a full table,
> with the notable differences marked with a red comment:
> *Infix operators in C*
> *In Swift 3*
> // skipping unary ops etc
> * / %
> * << >> // (!)*
> + -
> * &* / % *& // (!)*
> << >>
> + &+ - &- *| ^ // (!)*
> < <= > >=
> ... ..<
> == !=
> as as? is
> < <= > >= == != === !== ~=
> (default precedence diverges here)
> = @= // for various `@`
> = @= // for various `@`
> I think Jacob has a point in separating bitwise operations into their own
> hierarchy. I'd recommend doing so all the way, but retaining `&` with a
> higher "bitwise-multiplicative" precedence:
> 1) Move `|` and `^` into their own parallel precedence groups named
> *BitwiseOr* and *BitwiseXor*, just above RangeFormation.
> 2) Move `&` into its own group *BitwiseAnd*, just above both BitwiseOr and
> 3) Move *BitwiseShift* (i.e. `<<` and `>>`) just above BitwiseAnd.
> That would make it so that rarely occurring*) expressions mixing `^` and
> `|` would now need parenthesising, but either of them would work together
> with `&`, `<<`, and `>>` just like they do in C (and just the way binary
> addition relates to multiplication in the conventions of mathematics).
> *) E.g. none found in https://graphics.stanford.edu/~seander/bithacks.html
> Also integer arithmetic would stay clearly separated from bitwise
> operations, which in my experience is the source of most bugs and
> confusion. E.g. the expressions `a & b + c`, `a | b + c`, and `a << b - c`
> all compile in both C and Swift, but are parsed in exactly opposing ways.
> The whole hierarchy I'm proposing is illustrated in the attachment below,
> with all changes found in the top part above RangeFormation.
> — Pyry
> swift-evolution mailing list
> swift-evolution at swift.org
More information about the swift-evolution