4 ms·
The operator precedence in the article is just an example of a principle that does hold: A series of choices, each individually plausibly the right call, lead t
by rzwitserloot 7y ago
The operator precedence in the article is just an example of a principle that does hold: A series of choices, each individually plausibly the right call, lead to a bizarre situation that doesn't feel right.
However, often (and I submit this very article as exhibit A), the logic is reversed: One observes a bizarre scenario, points at it, and goes: I don't know what or how, but clearly somebody somewhere messed up.
That's not true; sometimes seemingly simple things simply aren't simple, and you need to take into account all users of a feature and not just your more limited view.
Take operator precedence. __operator precedence is an intractable problem__.
Some languages try to make it real simple for you and say that all binary operators are resolved left to right, and have the same precedence level. This makes it easy to explain and makes it much simpler to treat anything as an operator; a feature many languages have. Smalltalk works like this. The smalltalk language spec fits on a business card; obviously, you must use such principles as C's operator precedence table would otherwise occupy most of your card!
But that does mean that `1 + 2 * 3` is 9 and not 7, and that is extremely weird in other contexts.
So, you're in a damned if you do and damned if you don't situation: There is no singular answer: No operator precedence rule is inherently sensible regardless of the context within which you are attempting to figure out how operator precedence works: It is an intractable problem.
One way out is to opt out entirely and make parentheses mandatory. If you then also make it practical and say that the same operator associates left to right regardless of what operator it is, you can still write, say, `1 + 2 + 3 + 4`, but you simply aren't allowed to write `1 + 2 * 3` – you are forced to write `1 + (2 * 3)` or `(1 + 2) * 3`. But now anybody who feels they can copy problems from math domains, or from technical specifications such as a crypto algorithm description now gets tripped up. You may disagree (I certainly do), but a significant chunk of programmers just prefer shorter code. I would certainly prefer my languages to work this way, and have configured my linters like this as well, but it's still not a universally superior solution regardless of point of view.
In other words, had Ritchie chosen to go with this 'when in doubt, do not compile it' strategy, this article could not be written. And we'd still have programmers unhappy with how the operator precedence rules work.
- SAI_Peregrinus 7y ago> No operator precedence rule is inherently sensible regardless of the context within which you are attempting to figure out how operator precedence works: It is an intractable problem. I disagree. FORTH got it right. Postfix notation is inherently sensible, as any RPN calculator user will tell you. It eliminates the need for both precedence rules and parentheses, unambiguously. 1 2 + 3 * is 9. 1 2 3 * + is 7. It's infix notation that's the problem, precedence confusion is a consequence of it. (Prefix notation can work too, but requires more parentheses).
- rzwitserloot 7y agoAvoiding precedence issues is great. Absolutely. However, it's not crazy to want to write it like most humans are used to. I have no problem with the idea that it's more trouble than it sounds like, and '1 2 +' is the best answer to the dilemma. That still doesn't make it a slam dunk. Or should we start saying that just about every programming language out there has a major design flaw, in that it has infix and not postfix operators?
- xkriva11 7y agoSelf has such mandatory parentheses for mixed operators (binary messages)
- nwallin 7y agoPerfect is the enemy of good. The fact that it's intractable doesn't mean you shouldn't try to find a reasonable local optimum. For instance, if I have five minutes to code a traveling salesman implementation, I'll probably do a greedy algorithm that just does the closest city next until I've visited all cities. If I have more time, I might check that paths don't cross, and if they do, swap the order of the cities in that closed loop. That sorta thing. Is it perfect? Of course not. Is it better than throwing up my hands and saying the problem is intractable, therefore I should just return the list of cities in whatever order they were given to me? Absolutely. In the case of bitwise operators, Boolean algebra teaches us that & behaves like \* and | behaves like +. Therefore & should have the precedence of \* and | should have the precedence of +. Is this perfect, or as good as RPN? No. Is it better than a world where 'if (x & 0xff == y & 0xff) [...]' almost certainly does the wrong thing? Absolutely. If Ritchie had designed C to use postfix notation instead of prefix notation for expressions, it simply wouldn't have caught on. It would be as dead as FORTH. If he had designed it to have better precedence rules for bitwise operations, the world would be a better place. See also null terminated strings vs length prefixed strings. Length prefixed strings are not perfect. They are merely a lot better.