[swift-evolution] [Last second] Precedence of nil-coalescing operator seems too low

Vladimir.S svabox at gmail.com
Wed Sep 7 08:11:41 CDT 2016

On 05.09.2016 23:19, Xiaodi Wu via swift-evolution wrote:
> This suggestion has been pitched earlier and I've expressed my opinion in
> those earlier threads, but I'll repeat myself here:
> I'm hugely opposed to such changes to the precedence table. Those of us who
> work with bitwise operators on a regular basis have memorized their
> precedence in Swift (and other languages) and rely on such precedence to
> write readable, correct code without excessively nested parentheses. Any
> change here would break existing, carefully constructed code, punishing
> those who *have* put in the effort to learn the precedence table. To any

FWIW, I can't understand such an opinion. From my view this is a fragile 
code, you are saying about *writing* of the code, but code will be read 
much often than written.

The question is not how *you* good as developer and if *you* rememebered 
*all* precedence in Swift, but how many *bugs* will you have in 3rd party 
code, written by someone who not as good as you or probably just loose the 
concentration for one moment and written incorrect logic just because it s 
*so easy* to make such kind of mistakes.
And also the question is how your code will be understood by some other 
developer who will *read* your code and probably *modify* it later.

Currently we can have such a code:

let nextIndex = foundIndex ?? lastIndex + 1

let result = a || (b) ? isOne() : isTwo()

s << (x == 10) ? "10" : "not 10"

let i = 4 << 1 + 3

If we'll ask here in list for results for these lines, I believe we'll have 
a big number of people who will not answer correctly.

Swift *requires* to be careful in some situations, for example when working 
with Integer types, you can't "just" add Int and Int8, you have to 
explicitly case. Why? Because IMO Swift want to be safe(as much as 
possible) language, which helps to produce code without surprises, where 
you explicitly show your intention.

Do you really believe that the above code is clear about the intention of 
the developer and the *ability* to write such code don't open the door to 
hard-find bugs in code(not in your code, of course)

And about lints. They can help only for your own code in project.
Even if you added 3rd party code to your project as source, with lint 
you'll have to change all of such code and analyze logic in each 
questionable line (if this line is correct or there is a logical error). 
Plus, if you add 3rd party code as compiled framework/module you can't 
check it at all.

Yes, I do believe that Swift should require a parenthesis for any 
expression, where it is not clear what is the order of operations. Probably 
when we have an operations of different groups in the same expression. 
Exactly for the same reason - to make developer be clear about the 
intention of such code:

let nextIndex = foundIndex ?? (lastIndex + 1)

let result = a || ((b) ? isOne() : isTwo())

s << ((x == 10) ? "10" : "not 10")

let i = 4 << (1 + 3)

IMO much clear, I see *no* visual problems because of added parenthesis, 
only increased readability and my "parser" in head processes this faster

Again, there were (fixed now, I believe) a lot of logical errors(bugs) in 
well-known open source projects(I do believe there was code review for them 
and code most likely written by well-skilled developers) because of 
possibility to mix different groups of operators in same line without 
parenthesis (for example in Chromium,ReactOS,MongoDB,Apache Xerces 
Project,Unreal Engine 4,Wine,FreeBSD Kernel,Open X-Ray 
Engine,OpenJDK,CryEngine V,GCC). Again, not just because C allows to treat 
boolean values as integers, but because of mixing of operators.

I do believe Swift should be the language that prevent such 
"possible-buggy" code in all areas.

So, my suggestion is: produce a warning when operators from different 
groups mixed in the same expression without parenthesis. Or let's discuss 
another condition/method. This will not break the "old" code, but if you 
want to write not clear code and don't want to be explicit about your 
intention - you will produce code with warnings. Fair enough, I think.

Such kind of bugs is hard-to-find and IMO it is worth to have "warning" and 
to add parenthesis to prevent them not only in *your* code, but also in any 
3rd party code or in compiled framework/module.

To all: please provide your opinions on this subject, so we all can see if 
a lot of developers support my opinion(or don't).
Thank you for reading this.

> other user of Swift, it should come as no surprise that operators *have*
> precedence and associativity, and it is not such a burden for a user either
> to memorize or to consult a table for these properties when they are unsure.
> There is no way whatsoever to use intuition to arrive at the exact
> precedence of `??`, or `as`,or `&&`, or `||`, or `&`, or `|`, or `^` or
> `<<`, or `>>`, and there will be no relative precedence that will prove
> intuitive to all. (That said, there is a rational basis for the relative
> precedence of `&`, `|`, and `^` to each other.) If you believe this
> situation to be problematic, then you must conclude that we should remove
> relative precedence between any operators except perhaps the basic
> arithmetic operators `+`, `-`, `*`, `/`. This line of reasoning would be a
> huge U-turn from the direction of Swift, which after all just revised the
> syntax with which custom operator precedence is defined. Such a feature
> would be totally out of place in a language where operators other than
> those for basic arithmetic are not supposed to have precedence relations
> with each other.
> (Of course, the relative precedence of arithmetic operators is in some ways
> arbitrary as well, though it is inherited from math that everyone knows.
> How did you learn it in the first place? You memorized it.)
> On Mon, Sep 5, 2016 at 2:47 PM, Erica Sadun via swift-evolution
> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>     At this point, I'm not sure whether this is an -evolution question or a
>     -dev question. The latter would be much easier to work on at this time
>     and could potentially be postponed to a dot release. I know that any
>     conversation not directly related to 3.0 right now is a Bad Thing.
>     And I suspect that Steven C is probably the right person to know about
>     wrangling precedence and existing standards.
>     -- E
>>     On Sep 5, 2016, at 12:30 AM, Jacob Bandes-Storch <jtbandes at gmail.com
>>     <mailto:jtbandes at gmail.com>> wrote:
>>     Now you've gotten me thinking about precedence of other operators too.
>>     Since ?? is prone to causing confusion in either direction (cf. your
>>     example and my example), it could be put in its own group whose
>>     relation to the numeric operators is intentionally undefined (thus
>>     requiring parens).
>>     I don't know about other folks, but I'll certainly get confused if &
>>     and | and ^ are mixed. What if we removed their relation to each
>>     other (requiring parens when mixing them)?
>>     <proposed-precedence.png>
>>     For comparison (ha), here's what we have today:
>>     <current-precedence.png>
>>     Jacob
>>     On Sat, Sep 3, 2016 at 10:20 PM, Erica Sadun <erica at ericasadun.com
>>     <mailto:erica at ericasadun.com>> wrote:
>>>         On Sep 3, 2016, at 10:15 PM, Jacob Bandes-Storch
>>>         <jtbandes at gmail.com <mailto:jtbandes at gmail.com>> wrote:
>>>         Perhaps-conversely, what should this code do?
>>>             let nextIndex = foundIndex ?? lastIndex + 1
>>>         Jacob
>>         It's a good counter example. And there's no optional-associative
>>         option.
>>         -- E
>>>         On Sat, Sep 3, 2016 at 9:05 PM, Erica Sadun via swift-evolution
>>>         <swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>>>         wrote:
>>>             Given: `let x = Optional(3)` then
>>>                 `let y = 5 + x ?? 2` will not compile
>>>             but
>>>                 `let y = 5 + (x ?? 2)` will.
>>>             Should NilCoalescingPrecedence be raised? The current
>>>             operator precedence chain is:
>>>                 BitwiseShiftPrecedence > MultiplicationPrecedence >
>>>                 AdditionPrecedence > RangeFormationPrecedence >
>>>                 CastingPrecedence > NilCoalescingPrecedence >
>>>                 ComparisonPrecedence > LogicalConjunctionPrecedence >
>>>                 LogicalDisjunctionPrecedence > TernaryPrecedence >
>>>                 AssignmentPrecedence > FunctionArrowPrecedence > [nothing]
>>>             It seems to me that `NilCoalescingPrecedence` should
>>>             probably be higher than `MultiplicationPrecedence` and
>>>             possibly higher `BitwiseShiftPrecedence` as its job is to
>>>             produce an unwrapped value that can then be operated upon.
>>>             I think CastingPrecedence should be even higher because
>>>                 `expression as? T ?? fallback value`
>>>             should be parsed as
>>>                 `(expression as? T) ?? (fallback value)`
>>>             I apologize profusely because I know this is beyond last minute,
>>>             -- E
>>>             _______________________________________________
>>>             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>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

More information about the swift-evolution mailing list