[swift-evolution] [Last second] Precedence of nil-coalescing operator seems too low
xiaodi.wu at gmail.com
Wed Sep 7 08:46:09 CDT 2016
On Wed, Sep 7, 2016 at 8:11 AM, Vladimir.S <svabox at gmail.com> wrote:
> 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
>> 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.
(a) I don't believe so; (b) even if that were the case, it's *learnable*
(i.e. once you have learned it once, it is possible to remember); (c) it is
not the right test--there are plenty of functions that people would
struggle to understand without consulting documentation; but no one writes
or reads code using only Notepad, and with the use of a single table,
*everyone* can answer correctly. Compare this to the situation with
existentials, which involves high-level concepts regarding type systems: it
would take much more than a single table to help someone understand why
Self or associated type constraints prevent you from doing certain things
> 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.
I believe safe promotions are coming to Swift eventually; some of this is
intentional, but not all of the strictness here is by design.
> 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
There is nothing today that prevents you, or any careful developer, from
using the parentheses *as necessary*, and all evidence points to people
using parentheses as necessary and wisely. I am *not arguing* that these
parentheses are not good. However, if you remove precedence relations, then
you are *forcing* everyone to use parentheses, always, in all situations.
Unlike other parts of Swift, it isn't even possible to extend existing
precedence groups that don't have relations, like it's possible to extend
types you don't own.
> 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.
Can you provide examples that show this? The real-world example you
provided could not happen in Swift. Since you say that you know of lots of
logical errors that result from mixing of operators in these projects, can
you provide some examples from these projects that would also arise in
Swift? If so, you would persuade me of the problem.
> 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.
I think you are describing exactly the function of a linter.
> 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).
Previous threads have shown opinions on both sides.
In the period of a few months, there have been proposals to change the
precedence and to remove the precedence of <<, >>, &, | ^, is, as, ??, ..<,
..., &&, ||, ?:. This represents *all* non-arithmetic, non-comparison,
The promise of Swift 3 was that going forward, only essential
source-breaking changes would occur; here, nothing about operators has
changed since version 1, yet all of a sudden we are considering how to
fundamentally alter how they work. Existing code *will break*, and
sometimes silently, if such changes are made.
> 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
>> to memorize or to consult a table for these properties when they are
>> 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
>> 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
>> -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
>>> 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)?
>>> For comparison (ha), here's what we have today:
>>> 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
>>> It's a good counter example. And there's no optional-associative
>>> -- 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>>
>>>> Given: `let x = Optional(3)` then
>>>> `let y = 5 + x ?? 2` will not compile
>>>> `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 >
>>>> 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
>>>> -- E
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> swift-evolution mailing list
>> swift-evolution at swift.org
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the swift-evolution