I once asked my college professor about operator precedence in C. He had been writing C code in industry for decades.
"I have no idea" he told me.
He said many programmers try to make their code as short and pretty as possible, as if there was some kind of character limit. Instead of falling into that trap, he just used parentheses. And the order of operations never was an issue.
I agree with your prof, and have a peeve with linters that complain about unnecessary parens. They may be unnecessary, but they can sure be helpful for those of us who don't have the precedence tables fully embedded in our neural code scanners.
Even when I have no issues with the precedence order, I often add parens anyway because it helps with mental grouping at a glance, instead of having to scan and mentally parse the line.
As a young egotist I would often omit parens in complicated C expressions. I did this intentionally and in a very self-satisfied way - writing multi-line conditionals and lining them up neatly without parens with a metaphorical flourish of my pen.
Then one day, chasing a hard-to-find bug, I realised it had happened because I'd mixed up the precedence of && and || in a long conditional. I was an idiot. Since then I've made a point of reminding myself that I know nothing and that there's nothing to be gained from pretending I do, and putting parens in everywhere.
Sometimes, even now, I get those grandiose moments when I think the code I'm writing cannot possibly go wrong. Those are the moments that call for a bit of fresh air and an extra unit test or two.
That's a great observation. Passing on that expertise is what wizened veterans can do to move our capabilities along and not let learning go to waste. I've heard that a big reason for sometimes struggling software engineering quality in countries and companies is places where the only way to grow is to become a manager - you need people to stay in technical paths so they can pass on that learned knowledge.
Exactly this. I add parenthesis not for computer but for myself. Mostly because it is easier to comprehend. I think the reason for this is that I learned precedence order something like 25 years ago in fifth grade maths and still do it to this day.
If I were writing a linter I'd do the exact opposite: complain about a lack of parens if it might be confusing.
I don't know if a / b * c is (a/b) * c or a / (b*c). Don't tell me, no matter how many times I'm told I'll forget 5 minutes later.
Exactly. Linters often complain about the amount of whitespace as if readability was important, but then complain about "too much" readability of the operator precedence. Except one can cause a programming error while the other can't.
I have a peeve with linters in general. The useEffect dependencies lint rule for React is one the worst I’ve seen - “fixing” it changes the behaviour of your program. They are horribly opinionated and often leave you with less readable code. Bah
“Instead of falling into that trap, he just used parentheses.”
That’s my conclusion too. Especially when I deal with several languages at the same time I don’t want to spend time on thinking about these details. Makes my code a little more verbose but I think it adds clarity.
Some languages may have boolean types, where others evaluate non-boolean types as true/false. So do you say "if myflag" or "if myflag=true" to make sure it's valid?
And some languages don't have short circuit operators, which I find annoying, but have learned to work around. Should I then write C or whatever that way, when I do have short circuit and/or?
I try to be reasonable. There is probably no hard rule (a lot of people seem to want that) but you have to see where things are causing problems and then addressing them.
The moment you catch yourself adding parentheses to other people's code to be able to understand it, and then having to "git checkout --patch" to flip it back the way it was.
How often I wanted to apply the same to contracts and would wish to see it in legal texts as well. Parenthesis (and lists) would make legalese so much more readable and remove ambiguities. Still wondering why they do not use these tools.
I'm completely ignorant in the legal texts/contracts area, but they don't use parenthesis and lists? That seems hard to believe - or is it that they just don't use it to indicate precedence and order?
Canons of legal construction exist because of ambiguity in human language.
Here are a few that illustrate common imprecision in language.[0]
Conjunctive/Disjunctive Canon. And joins a conjunctive list, or a disjunctive list—but with negatives, plurals, and various specific wordings there are nuances.
Last-Antecedent Canon. A pronoun, relative pronoun, or demonstrative adjective generally refers to the nearest reasonable antecedent.
Series-Qualifier Canon. When there is a straightforward, parallel construction that involves all nouns or verbs in a series, a prepositive or postpositive modifier normally applies to the entire series.
Nearest-Reasonable-Referent Canon. When the syntax involves something other than a parallel series of nouns or verbs, a prepositive or postpositive modifier normally applies only to the nearest reasonable referent.
Proviso Canon. A proviso conditions the principal matter that it qualifies—almost always the matter immediately preceding.
General/Specific Canon. If there is a conflict between a general provision and a specific provision, the specific provision prevails (generalia specialibus non derogant).
How would one parse "if A and B or C"? You'd want to add parentheses "(A and B) or C"; or "A and (B or C)". For a simple case, a comma might suffice, but more conditions can get difficult to express unambiguously in plain language.
Indeed, this is the pattern most industry programmers follow: never rely on operator precedence and always uses parentheses to disambiguate where things aren't glaringly obvious.
That makes your code both more robust and maintainable.
You should write your code with consideration for the next person tasked with maintaining it. If for some reason you can't manage that (?!?), I suggest coding with consideration for _yourself_, six months from now, still slightly drunk at 2am when the page comes through...
Joke aside, I use parentheses liberally. Even if I know operator precedence it saves me from errors when I edit the code and another person reading it might not know precedence rules perfectly.
* Unary suffix operators (C doesn't have these, but Rust's ? operator applies)
* Unary prefix operators
* Arithmetic operators, following normal mathematical precedence rules (i.e., a + b / c is a + (b / c), not (a + b) / c). Note that I don't have any mental model of how <<, &, |, ^ compare to each other or the normal {,/,%}; {+,-} rank.
Comparison operators
* Short-circuit operators (&&, ||)
* Ternary operator (?:)--and this one is right-associative.
* Assignment operators
This list I think is fairly objective, although C and some of its children "erroneously" place bitwise {&,|,^} below comparison operators instead of above them. The difference between suffix and prefix unary operators is somewhat debatable, but it actually does make sense if you think of array access and function call expressions as unary suffix operators instead of binary operators.
Those show why I called it a heuristic. With some code similar to yours, I would probably use parentheses unless they are frequent enough to deserve some brain cells.
I certainly always always always used parentheses in situations like these back in the day. More because it was the idiom I learned early, rather than a conscious decision to be risk averse or professional.
(...Over the reals. Your mileage may vary in less exact types. The Surgeon General recommends avoiding division in production code. Regulations vary by state.)
That's kind of one problem with it, it's less PEMDAS and more P, E, MD, AS. Multiplication and division don't have precedence over each other and neither does addition and subtraction. Both of those go from left to right.
Obviously yes, but that is question-begging. How does the novice programmer know that it is a good practice to use parentheses? x + y == z is correct, so it seems reasonable to conclude that x & y == z is also correct, particularly when the compiler does not complain about it.
How does the novice programmer know about order of operations? Maybe they are blissfully unaware of both features, but if someone is being taught one feature, they should be taught both. In my case, I'm self-taught and just applied what I learned in basic algebra about parens and boolean logic.
With an answer like that he would no doubt flunk the modern interviewing process:
"We had a guy come in, tons of experience, aced all of our coding tests... but when we asked him about operator precedence in C, he just shrugged and said 'I have no idea'. So we had a to let him go, for his lack of strong CS fundamentals."
Said one 25 year-old SSE to another in the follow-up.
Interviewing skills are a thing like everything else. A good candidate should jump to the opportunity to explain why she can't trust even herself to do it right (let alone other people, including her future self!). Brining (or making up plausible) examples from experience, etc.
Yes, sometimes it's silly, but there is the harsh reality of how interviewing is executed, especially by those companies who want to base the assessment mostly on the judgement of peers as you said.
If you're really senior, in most cases, you can't expect that the majority of people in the company you're applying to is going to be as senior as you. You'll need to do a lot of convincing and explaining of things that might be obvious to you even after you join, on a daily basis. As with everything, the interview can be a good place to show you can do it.
Knowing the precedence and knowing it well is necessary so that you can read code quickly and accurately. Not so that you can write code using the minimum number of parentheses.
Sometimes, even when you have the power to add parentheses to existing code and merge the commit, you still have to know what the unmodified code is doing: just so that you're sure your readability improvement is not changing the behavior, for one thing!
You can be looking up precedence tables all the time, or adding prints to test things empirically run-time.
"I have no idea" he told me.
He said many programmers try to make their code as short and pretty as possible, as if there was some kind of character limit. Instead of falling into that trap, he just used parentheses. And the order of operations never was an issue.