Live data from Hacker News

Dennis Ritchie on the priorities of && || vs. == etc. (1982)

lysator.liu.se

41–50 of 178 posts

Re: Dennis Ritchie on the priorities of && || vs. == etc. (1982)

#41
post #9

The relative priorities of && vs ||, or & vs |, match the traditional precedence in logical expressions: "and" binds more tightly than "or", just as * binds more tightly than + ("and" is equivalent to * for one-bit values, and "or" is addition modulo 2). So I think that they got this correct. However, the precedence of & vs &&, or & vs ||, etc is a source of problems.

> However, the precedence of & vs &&, or & vs ||, etc is a source of problems.

Do you have any examples of this? In my experience you almost always want the bitwise operators to have a higher precedence than the logical operators, as using the result of logical operators as a bitmask makes little sense. Consider e.g. `A & B && C & D`, which currently is equivalent to `(A & B) && (C & D)`, but with reversed precedence would be equivalent to the almost nonsensical `A & (B && C) & D`.

Now, the precedence of == with respect to & and | is actually problematic (as Ritchie admits as well). Having `A == B | C` interpreted as `(A == B) | C` is almost never desirable. For extra annoyance, the shift operators do have higher precedence than comparison, so `A == B << C` does what you usually want (`A == (B << C)`).

Re: Dennis Ritchie on the priorities of && || vs. == etc. (1982)

#42
post #8

Earlier quoted context omitted.

Convert them to arithmetic. If you ignore the casting, a && b is just a * b a || b is just a + b Now you remember the precedence between them (except in broken languages, of which the only notable one is shell).

Is there an intuition for this correspondence otherwise I don't think it's very helpful

Yes, sometimes logical AND called logical multiplication and logical OR called logical summation.

It seems clear for me, because I remember learning De Morgan's Laws in electronics class and from one specific level of Turing Complete game.

Re: Dennis Ritchie on the priorities of && || vs. == etc. (1982)

#43
post #38

Earlier quoted context omitted.

Is there an intuition for this correspondence otherwise I don't think it's very helpful

There is: The neutral element for + is 0 ( x + 0 = x for any x ). The neutral element for * is 1 ( x * 1 = x for any x ). Furthermore, you have arithmetic properties like x * 0 = 0 for any x (annulation) or ( x + y ) * z = ( x * z ) + ( y * z ) for any x , y , z (distributivity). Similarly: The neutral element for OR is false ( x OR false = x for any x ). The neutral element for AND is true ( x AND true = x for any x…

I've never heard of saturation arithmetic and now it all makes sense. Otherwise I thought it was more common to think of XOR as boolean addition, and OR would be represented as xy + x + y.

Re: Dennis Ritchie on the priorities of && || vs. == etc. (1982)

#44
post #9

The relative priorities of && vs ||, or & vs |, match the traditional precedence in logical expressions: "and" binds more tightly than "or", just as * binds more tightly than + ("and" is equivalent to * for one-bit values, and "or" is addition modulo 2). So I think that they got this correct. However, the precedence of & vs &&, or & vs ||, etc is a source of problems.

& vs && doesn't feel like a problem to me.

& vs == is the real problem: `(val & MASK) == CONSTANT` needs parentheses due to this mistake.

`a & (b == c)` essentially almost never makes sense (== gives you a boolean, and when dealing with booleans you can use && instead), yet that it what you get by default if omitting the parentheses.

Re: Dennis Ritchie on the priorities of && || vs. == etc. (1982)

#45
post #4

Somewhere, I sat down and wrote a combined precedence table across many languages. It was quite hairy; sometimes there's even variation across language versions. Besides `not` (which often has different precedence depending on whether it's a keyword or a punctuator, and is a great reminder that multiple levels of pratt parsing is meaningful), `await` is the one with the most variation - in most languages, it binds ti…

> `await` is the one with the most variation [..] in C++ it's just barely tighter than assignment.

That doesn't seem right to me. According to cppreference[1] it's the operator with the third-highest precedence, well above assignment, which is the second-lowest.

[1] https://en.cppreference.com/w/cpp/language/operator_preceden...

Re: Dennis Ritchie on the priorities of && || vs. == etc. (1982)

#46

Earlier quoted context omitted.

Is there an intuition for this correspondence otherwise I don't think it's very helpful

IMO the intuition is to not use any intuition at all: there aren't built-in booleans in C, true is a #define for 1 and false is a #define for 0. For C conditionals, 0 = false, nonzero = true. So a+b != 0 a!=0 or b!=0 a*b != 0 a!=0 and b!=0 Of course this intuition also reveals the pitfall behind this correspondence! You'd better make sure those are unsigned ints or #defined booleans, so you're not using general C exp…

"true is a #define for 1" is bad idea. Because when `x` is, say, `2` then `if x` is not the same as `if x==true`.

Re: Dennis Ritchie on the priorities of && || vs. == etc. (1982)

#47
post #38

Earlier quoted context omitted.

Is there an intuition for this correspondence otherwise I don't think it's very helpful

There is: The neutral element for + is 0 ( x + 0 = x for any x ). The neutral element for * is 1 ( x * 1 = x for any x ). Furthermore, you have arithmetic properties like x * 0 = 0 for any x (annulation) or ( x + y ) * z = ( x * z ) + ( y * z ) for any x , y , z (distributivity). Similarly: The neutral element for OR is false ( x OR false = x for any x ). The neutral element for AND is true ( x AND true = x for any x…

There's also a connection to probability: if you want the probability of A and B and C happening and they're independent, it's P(A) * P(B) * P(C). If you want the probability of A or B or C happening and they're mutually exclusive, it's P(A) + P(B) + P(C).

Similar analogue for set theory, as another commenter pointed out.

Re: Dennis Ritchie on the priorities of && || vs. == etc. (1982)

#48

this is why lisp is beautiful

Indeed. But lisp is much more than prefix notation.

Different notations like revers polish notation also easier to parse. You can evaluate RPN only using stack.

Also, recently I learned about thread-last macro in emacs lisp. Using it you can evaluate forms from left to right, and using it you can write less parenthesis.

Re: Dennis Ritchie on the priorities of && || vs. == etc. (1982)

#49

There's a niche language called Sail that has & and | act as both bitwise and boolean operators. It actually works really well and isn't confusing at all after the initial "this is different". There's no real downside because it is a modern strictly typed language unlike C. On the other hand I don't know if there's a real upside either. It's not very difficult to use && and || and it serves as extra documentation, an…

I'm not familiar with Sail, but the reason for separate logical operators is that you want short-circuiting behavior. For example, in:

    (a != NULL) && a->x
You don't want to right-hand side to be evaluated if the left-hand side is false.

Re: Dennis Ritchie on the priorities of && || vs. == etc. (1982)

#50

There's a niche language called Sail that has & and | act as both bitwise and boolean operators. It actually works really well and isn't confusing at all after the initial "this is different". There's no real downside because it is a modern strictly typed language unlike C. On the other hand I don't know if there's a real upside either. It's not very difficult to use && and || and it serves as extra documentation, an…

Well in C-derived languages && and || will short-circuit the evaluation whereas & and | will not.

Aside, In Oral Tradition in Software Engineering by Bryan Cantrill, he talks a bit about the lack of logical xor in C. https://youtu.be/4PaWFYm0kEw?t=2236&si=MZPbopZPQtnnT-Tb
Post reply on HN