|Perl Monk, Perl Meditation|
Re^4: Thoughts on using and, or, and not over && || !? (parens)by tye (Sage)
|on Jul 16, 2016 at 00:27 UTC||Need Help??|
You meant to type:
You could theoretically teach people to use parentheses everywhere, but much of the resulting code would be completely unreadable (worse than LISP). "Never use parens" is, of course, not really an option. It isn't just that some constructs require parens for reasons other than clarifying precedence: ( 1 ) x 10. So, $a*$b + $c gets parsed in agreement with the spacing I used. If I want to instead calculate $a * $b+$c, then I should just add parens: $a*( $b + $c ); those ones aren't a matter of taste. There are more convoluted ways to avoid such parens, but always going that route is beyond just a "style choice".
Whether parens "clutter" or "clarify" is a matter of taste
Well, I can concur that "one set of parens vs. zero parens" in many cases boils down to a matter of taste. But more than 2 levels of parens does not "clarify", for most people. As I said recently, I have had (only a couple of) people tell me that they have no problems matching up deeply nested parentheses. But I actually tested them by showing them code with and without parentheses and they were unable to quickly find the bug in the code with parentheses 3 or 4 levels deep. There certainly could be some people who can really do that, but my experience is that such people are so rare that I've not yet met one. So I don't find it wise to use "extra" parentheses. And I often find it wise to go the more convoluted routes when code ends up actually needing 3 or more levels of (required) parentheses.
Nor do I advocate "memorize the precedence table". I find memorizing is usually a poor choice in general. A much easier approach is "understand the precedence table". It is quite easy.
So, there are a lot of utterly mundane coding situations for which the precedence table was well designed. In such mundane situations, adding parens because you haven't bothered with the small effort to learn how precedence "just works" there can make the code harder to parse for the majority of people.
For the non-mundane coding situations, sure, add clarifying parens. But almost always avoid nesting them deeply.
If you are masking bits, then sure, use maximal parens and if you end up with 3 or even 4 levels of parens, then just make sure your expression is short enough and use spacing to aid visual parsing. The precedence of bit operators is, well, just wrong. So, even if one set of parens is not required when masking bits, include them anyway because understanding that part of the precedence table is more of a lesson in history than in anything logical and we shouldn't require people to understand obscure bits of history (or to go read the table again) in order to understand your code.
'and', 'or', and 'not' are for flow control between "statements" and so have the lowest precedence. You are also allowed to use comma to separate "statements". Comma binds tighter than 'or' (etc.) otherwise "open FOO, ... or die ..." would be parsed wrong.
Assignment is one of the most common types of statements and you might want to assign a boolean value so assignment operators bind the next most loosely. (So you need to use parens if you want to do an assignment that involves commas.)
?: takes a logical expression as an argument so it goes next. Then we have the logical operators (mostly '||' and '&&') that are often used to combine comparisons. So comparison operators come after those. (So you should use parens if you want to use an assignment as part of a comparison or logical expression.)
Then we have mundane expression operators.
Add to this the preference of mathematicians that '*' binds tighter than '+' and that 'and'-like operations are like '*' and 'or'-like operations are like '+', and you've got almost all of the sane details of the whole precedence table down. (Mathematicians also prefer unary operators to bind tighter than binary ones.)
Anything that isn't clear from that is at least a candidate for adding parens, even when they aren't needed. So you write "Found " . ($last+1) . " items". Though, I'd actually instead write that as join ' ', "Found", $last+1, "items" (which is a reason why die takes a list not just a single string and why your 'print'-like routines should as well).