Tight syntax from a readability perspective
When reviewing the code for a massive new feature for Bugzilla, a question on the proper way to write logic stepped up again. Do we use the ternary conditional operator ?:
? Do we use explicit boolean constants true and false instead of relying on expression results? Let me demonstrate the issues encountered with some equivalent snippets of code. Assume this is C#, but C++/Java/Perl etc. wouldn't differ much.
// Style 1: The most verbose public bool isEvenInteger(int num) { if (num % 2 == 0) return true; else return false; } // Style 2: Use ?: instead of the if conditional public bool isEvenInteger(int num) { return (num % 2 == 0) ? true : false; } // Style 3: Discard ?: public bool isEvenInteger(int num) { return (num % 2 == 0); // C++ posse would say just "!(num % 2)" }
So the question: Which one of these is the most readable?
For the beginning programmer, one is tempted to think about style 1. After all, in that example, the only non-english things are the % (modulo) operator and the use of double ='s – but once you know them, it's pretty clear-cut. On the other hand, style 2 is much more compact. It uses the ternary conditional operator, where a ? b : c
is roughly equivalent to if (a) b; else c;
.
Since the a
part – the condition of the ?: operator – is always a boolean expression, the ?: operator is useless when you want to return a boolean value. In fact, ? true : false
can always be removed, and ? false : true
can always be replaced with a not operator. And because of this, most programmers with some experience pick model 3, which is terse and compact.
And that marks the kickoff on the discussion of whether code is too tightly-packed (for readability) after all unnecessary parts are discarded. For the C++ form briefly noted in the example, I think it is. For the uncommented version of style 3, I'm inclined to say no. Here's some argumentation on the issue.
Tightness is readability, too (in code)
People often fear ?: because of its unnatural syntax. To some extent, this is also caused by misuse of the operator: f.e. construction of switch
trees with it almost always results in unreadable code. Also, ?: is a prime candidate for obfuscating your logic. But that's not to say it couldn't be useful: terse syntax is not necessarily an enemy of readability. Take a look at the following typical code examples:
int age = AGE_NOT_GIVEN; if (userinput_age > 0) age = userinput_age; // vs. int age; if (userinput_age > 0) age = userinput_age; else age = AGE_NOT_GIVEN; // vs. int age = (userinput_age > 0) ? userinput_age : AGE_NOT_GIVEN;
Upon closer inspection, any programmer easily understands any of these structures. The first of them is probably the worst, as it forces the reader to both evaluate the first (default value) assignment, then think about the if condition and the other assignment inside the conditional block. The second one makes it much more clear that age is assigned either of the two values, so it beats the first one.
But both of the two first styles have one drawback: At a glance, it's not easy to tell that the age is assigned a value. The if blocks could contain whatever code, so you have to read through them to see that age value is actually getting assigned. With the third form, the first 10 characters tell you age is getting assigned: thereafter it's just a question of what's the value it gets assigned to.
When looking at the code from a more general perspective, you're not interested in the details; you're interested in the generic flow of things ("first age gets assigned, then WibbleMyToes(age) is called, after which the return value is saved"). The more pages you have to go through, the more time it takes. So, using compact syntax for logical trivialities avoids stealing focus from more important issues. And yes, this means there is a consequent rule: Do not try to pack logic that is critical to understanding the code flow. I believe most of the bad examples of using ?:
stem from breaking that rule.
That said, it's also easy to see why you shouldn't write ? true : false
: It is just another way to emphasize trivialities, just like unnecessary commenting in the spirit of i++; // Increment i by one
.
The conclusion
Full circle is easy to achieve here: Beginning coders mostly (have to) focus on the code at the statement level. Advanced developers have already devised a skill to read code one page at a time. Let's return to the first set of examples. While the first style is probably the most readable form for beginners, it degrades the code browsability in the long run. The last one may take some time for beginners to read, but it is precise, to the point and exactly as unnoticeable as it should be.
There will always be somebody whining about using language features such as the ?:
operator. That's understandable. People are bound to complain, because the tight syntactical structures are something they can point at. If you expand all the code, the big picture may still be unreachable for them (because of the length and depth in the code), but they're more likely to blame themselves as they can't spot a single culprit for their lack of understanding. It takes quite a lot of programming experience to come up with opinions like "You're commenting too much here" or "You should tighten this syntax".
Of course, no rule is a silver bullet. If your conditions get really long or if they're particularly critical for the software's functionality, use an if block – at least the structure of an if statement leaves you much more room for useful comments.
Also, everything said above shouldn't fool you into thinking there is a single correct way to do things. There isn't. These are all just factors in a bigger game of selecting a coding style and being consistent with it. That's one of the more interesting challenges in developing open source software – with a developer group of insanely varying backgrounds and competence.
July 25, 2004
В·
Jouni Heikniemi В·
One Comment
Posted in: Misc. programming
One Response
Max K-A - July 27, 2004
I think that's a really good point, actually, and really well said.
I generally would avoid ?: before, but I think that it makes good sense to use it in the situations that you've described. I think you've come up with a good rule of thumb for it, too.
-Max
Leave a Reply