I was watching engineers argue, someone was bitching about a code reviewer asking him to put more parentheses in a conditional: “As if I don’t know the precedence rules!” I don’t know them, as a matter of principle.
Seriously. I’ve learned a lot of programming languages over the years, and I’ve taken care never to learn the operator precedence rules in any of them. It’s easy to get them wrong and get bitten and why should I require that people reading my code learn those stupid rules. Today I wrote this:
while (calls.moveToNext() && (count < howMany)) {
I sorta kinda think that the parentheses after the &&
are superfluous, but being sure would mean memorizing something that adds no
value and furthermore require that subsequent programmers do the same.
So for the last couple of decades I’ve just put all the parens in, regardless.
A related case: I have never bothered to learn, nor will I, what the
default modifiers for Java’s variables and methods are. Thus, every one of
those things gets one of private
or public
or
protected
in front of it. There are way better things to load up
the finite cupboard-space in my mind with.
No, I don’t think it’s a big deal; just saying.
Comment feed for ongoing:
From: Dominic Mitchell (Jun 29 2010, at 22:49)
Whilst I agree, there is at least one situation where you _have_ to use the default: package-private access.
[link]
From: Geoffrey Wiseman (Jun 29 2010, at 22:50)
While I definitely agree with your main point, the default modifier for members of Java classes is unfortunately a modifier that you cannot specify explicitly, so the only way to get that particular effect is to leave out the modifier.
[link]
From: Default Java visibility (Jun 29 2010, at 22:50)
You may want to reconsider learning the Java visibility model - the default access level for Java members is none of public, protected or private - it's something different (it makes things visible to other classes in the same package): http://www.ibm.com/developerworks/library/ws-tip-mem-visibility.html
Very (very) occasionally you might want to use it instead of one of the standard modifiers.
I understand and agree with your point though (and I think this was something badly designed in Java).
[link]
From: Luis Miranda (Jun 29 2010, at 22:54)
Java's a bit different in that the lack of a visibility modifier indicates "default" visibility, which is neither public, protected, nor private (a 4th level).
But yeah, point taken.
[link]
From: Alex Pretzlav (Jun 29 2010, at 22:54)
Sadly in Java the default modifier is none of those. It's package private, which happens to be handy for unit tests and nothing else.
[link]
From: Dan Fabulich (Jun 29 2010, at 22:55)
The Java default is its own FOURTH thing; it's not private, public, nor protected, but "package-private;" anyone in the same package can access it directly. It's quite useful for unit testing.
Surprisingly, there's no other way to get package-private protection except to accept the default by not declaring a keyword.
It's quite unfortunate that such a useful feature is hidden in a default. On the other hand, it shows that sometimes it's worth your while to learn the defaults!
[link]
From: Jim (Jun 29 2010, at 22:56)
Correctness, followed by readability.
Parentheses are fine up until parentheses-itis has me spending more time balancing parentheses than actually reading the code.
Knowing operator precedence is still necessary for reading code written by someone else, and figuring out what they intended. (Especially useful to know their intent when you've ultimately got to fix their code.)
[link]
From: Trevor Bramble (Jun 29 2010, at 23:13)
Definitely falls under "optimize for maintainability".
Using the parentheses, required or not, clearly communicates your intent to anyone reading to code.
Likewise, not explicitly declaring visibility leaves your intent ambiguous. Later readers will wonder if the omission was deliberate and if not, what the visibility should have been/should be.
I'd still suggest knowing the precedence rules so you can better understand code you come across from less enlightened authors though. =^)
[link]
From: George Phillips (Jun 29 2010, at 23:54)
And yet you seem to know the precedence of the "." and "()" operators. I'll bet you even carelessly write "a = b + c;" expecting others to somehow know that plus has higher precedence than assignment. I myself am guilty of never using the "auto" keyword in C programs.
Absurd you may say, but my point is that we all draw the line somewhere. Personally, I think it perfectly reasonable to insist that "a + b * c" is well understood but others have vehemently disagreed.
But what I really wish is that editors or IDEs would help out here. They'll show you matched parentheses all day long but never even whisper about those that are implied or extraneous.
[link]
From: Jesse Wilson (Jun 29 2010, at 23:56)
This one's my favourite:
int x = ...;
int halfX = x>>1;
int threeHalvesX = x + x>>1;
[link]
From: IBBoard (Jun 30 2010, at 00:58)
Package visibility is one thing that annoys me in C#. Unlike Java, no modifier defaults to "private" in C# (and probably all of .Net) and so the Mono guys insist that putting "private" there to make your intent explicit is wasteful. I use C# as a hobby and Java for my work and so I'd rather see "private" everywhere to make it clear. Someone even compared the use of explicit "private" in C# to horribly over-engineered industry code, where was without them it was the work of an artist(!)
As for the brackets, I might not do as many as I could, but I do agree that some people assume too much with operator precedence and other developers, which does come back and bite you later.
[link]
From: Sterling Udell (Jun 30 2010, at 01:03)
One other point on the Java scope issue: the default (package) scope may, in certain circumstances, be higher-performance in Android. See here: http://developer.android.com/guide/practices/design/performance.html#package_inner
Also, notice that the code sample there has a good practice for making your intent clear when using the default (package) scope in Java:
/*package*/ static int foo;
[link]
From: Martin Probst (Jun 30 2010, at 01:33)
My group has the not-really-enforced rule of always using parenthesis and never relying on operator precendence, and I think that is the right way to do it (tm).
I also think one should explicitly initialise all variables (or at least the primitive ones), even if you know that a boolean field will default to false - being explicit about it gives another tiny bit of readability.
[link]
From: Ed Davies (Jun 30 2010, at 01:41)
Wirth deliberately made the precedence hierarchy in Pascal pretty flat for exactly the reasons you suggest. Knowing this I've never been embarrassed about not memorizing the rules and just using a few redundant parentheses to make sure.
Similarly, I can't be bothered with all the different ways values evaluate to true and false in different languages (null/none/undefined/[]/{}/""/NaN/0... in each of JavaScript/Python/XSLT/C++ I've used recently) and always write explicit tests: even "while (*psz != '\0')" rather than "while (*psz)" as many would choose.
[link]
From: John Cowan (Jun 30 2010, at 04:30)
Do you really write a + (b * c) instead of a + b * c? "Multiplication/division before addition/subtraction before relational operators before logical operators" is safe in every language I know except Pascal (where the logical operators are overloaded * and +) and APL (where there is no priority of operators, and everything is done right to left). For everything else, I use parentheses.
[link]
From: Keith Gaughan (Jun 30 2010, at 04:58)
Could I suggest that heavy use of parens in an expression is an indication that at least part of the expression should be separated out into a function? I'm not one of those who wraps every subexpression in its own pair of brackets, but I've found that when I'm tempted to do so, it's almost always an indication that it ought to be broken up.
[link]
From: dr2chase (Jun 30 2010, at 04:59)
You'd no doubt be amused, perhaps pleased, by the Fortress parsing rules. These two statements are legal (not sure how this will survive character-mapping and text massaging, but here goes):
e = a b + c d
e = a⋅b + c⋅d
These two are not:
e = a b+c d
e = a ⋅ b+c ⋅ d
In the second example, spacing cues do not match default precedence, therefore it is a syntax error.
[link]
From: fbaube@yahoo.com (Jun 30 2010, at 05:04)
Precedence rules are background noise
[link]
From: Michael Harrison (Jun 30 2010, at 05:50)
Tim,
Your attitude is a perfect match for a language that has no operator precedence rules, where parens are used to group operators with arguments. I think your ideal language would also allow you to use your command of Java through powerful and clear interop mechanisms. You could even convince your fellow Googlers to take up this mighty tool to increase their productivity.
Now if only there were such a language... It all sounds vaguely familiar. :-)
[link]
From: Martin (Jun 30 2010, at 06:39)
I agree, mostly in C.<br>
I rather write:
<pre>
if(ptr == NULL) {}
</pre>
than
<pre>
if(!ptr) { }
</pre>
The compiler generates the same code (good to know assembler) and it is much easier to read.
[link]
From: Douglas McClean (Jun 30 2010, at 06:49)
I agree entirely on operator precedence. I actually think some languages should not even define an operator precedence relation and would be better served by requiring parentheses anywhere that there might be an issue.
[link]
From: Ryan Walker (Jun 30 2010, at 06:59)
My first reaction is to replace (count < howMany) with a one-line predicate method (pseudocode in Ruby)
def enough?
count < howMany
end
Isn't that more clear than the parenthetical expression?
[link]
From: Andy Lee (Jun 30 2010, at 07:34)
I'm the same way about parentheses. Another reason is that in many text editors and IDEs it's easy to select a parenthesized expression by double-clicking the parentheses. This helps me check that a complex expression is structured the way I think it is, by highlighting each subexpression.
[link]
From: len (Jun 30 2010, at 07:45)
"There are way better things to load up the finite cupboard-space in my mind with."
That was my opinion of learning the minimization in ad hoc SGML type defs. It was easier to type the end tags, quote the attributes and get on with life.
[link]
From: Phil (Jun 30 2010, at 08:17)
Deep down inside you're a lisper at heart.
[link]
From: Fernando (Jun 30 2010, at 09:01)
Yet another issue that doesn't exist on Lisp languages. Go back to Clojure Tim!
[link]
From: brian bulkowski (Jun 30 2010, at 09:34)
Huzza huzza! I agree 100%. I would rather not write a precedence bug: they're hard to find.
I hit this pain on the Network for Macintosh router project in 1992. There was a long-running bug in the codebase we used, a loop eval statement that was evaluated the wrong way. Hatefully, the code worked, but was n^2 unexpectedly. When the router was introduced in the largest appletalk network in the world at the time (Boeing, as I remember), there were many problems - finally tracked down to that precidence flaw. Compilers will never help you, runtime analysis may or may not.
I also don't learn precedence because I switch between languages too often. In and out of python's the worst, because my fingers stop typing ';' in Python and it takes an hour or two before 'auto ';'' comes back.
[link]
From: Kevin Q (Jun 30 2010, at 11:26)
I actually found the "default" variable modifier isn't that hard to remember, but I absolutely agree with you on operator precedence. It should only be for language designers, and it (operator precedence) should be designed in a way that invoke the least surprises (aka follow common sense).
[link]
From: Juegos Gratis (Jun 30 2010, at 13:09)
As others mentioned, you use precedence without even realizing it such as the . and = operator. I basically do the same as you except I also assume multiplication/division takes precedence over addition/subtraction as that is pretty standard across all languages.
Your point is well taken though, that the extra parenthesis cost nothing at compile-time and almost nothing at coding-time, so WHEN IN DOUBT: USE PARENTHESIS.
[link]
From: Neil Conway (Jun 30 2010, at 13:16)
Like many things in programing, I think this is ultimately a question of style and good taste; dogma like "forget all defaults" is no more sensible than encouraging programmers to memorize and depend on the minutiae of the precedence table. Would you suggest that C programmers declare their ints to be "signed int", to avoid the reader needing to recall the default sign?
I think there's an analogy to be drawn between prose: using a larger vocabulary (or technical jargon) imposes a somewhat higher burden on the reader, but often allows you to express yourself more briefly and concisely.
[link]
From: John Hart (Jun 30 2010, at 17:31)
[QUOTE]
From: Ryan Walker (Jun 30 2010, at 06:59)
My first reaction is to replace (count < howMany) with a one-line predicate method (pseudocode in Ruby)
def enough?
count < howMany
end
Isn't that more clear than the parenthetical expression?
[/QUOTE]
I'm not sure if this is a joke or not, but if serious, I disagree.
This suggestion takes a concise expression and replaces it with a function call which the reader then needs to find & read to understand the original intent.
It also assumes that "count" and "howMany" are encapsulated in some sort of state object (a "real" object or closure) so that enough? can reference them.
Stateful methods are a necessary evil. When they aren't necessary, they are merely ... evil.
[link]
From: Robert Young (Jun 30 2010, at 17:37)
Here, here. Explicit beats implicit every day. And "defaults" add nothing to either execution or readability.
[link]
From: Bill Robertson (Jun 30 2010, at 18:34)
Meh.
Ignoring them completely is as dumb as learning them all and insisting on coding to that standard, even when its not clear.
[link]
From: David Tkaczyk (Jul 01 2010, at 07:24)
Amen to this short but elegant entry... readability and maintainability too often take a back seat. Plus, I am sure that my cupboard has less capacity than yours to begin with ;)
[link]
From: Tony Fisk (Jul 01 2010, at 08:00)
The only time I have been asked about operator precedence is during job interviews. My response is usually along the lines of:
'Just shove a (bezoar) in it!'
A bigger concern is that people are still willing to spend large amounts of time reviewing code... and coming up with these pernickety comments. I suppose it shows they're paying attention but I believe it misses the fundamental point, which is 'can I understand what's going on?'
[link]
From: szeryf (Jul 01 2010, at 22:46)
Not that I want to argue with the general rule but the example you gave just wouldn't compile if the precedence rules worked differently than what you specify with parentheses. If you take into account what types those operators expect and return (&& expects two booleans and returns a boolean, while < expects two numbers and returns a boolean), there is no other way to parse this expression. So that's why I wouldn't uses parentheses in this case.
[link]
From: Paul W. Homer (Jul 05 2010, at 09:27)
I'd consider the extra parenthesis in:
while (calls.moveToNext() && (count < howMany)) {
to be unnecessary noise that is (only slightly) making the code harder to read. Any sane language designer would put any conditional operators (<) ahead of any 'connective' operators like &&, so unless proven otherwise I'd always make the assumption that they work normally. In a code review I'd ask the above (which I consider pedantic) to be changed to the more natural:
while (calls.moveToNext() && count < howMany) {
which, because of less noise, is more readable. Less is always best.
Paul.
[link]