Posted tagged ‘technical audience’

The Art of Writing Good Conditionals

September 2, 2009

Based on my experience, many of the finer points of writing optimal conditional statements are not covered in most introductory computer science courses. For that reason, I thought I’d go ahead and write a post on the topic. There are other points that I will not be covering, but I’ll offer some advice on how to write great conditionals and I’ll show a few tricks on how to optimize your conditional statements. Keep in mind that conditional statement optimization is a form of micro-optimization and that performance gains from macro-optimization (ie. Good design, optimal data structures and algorithms) will be much greater. The code examples will be written in Java, for concreteness.

Common Mishaps

These are two simple examples of bad practices that should be avoided.

If you have a Boolean b, use it directly! Do not compare it with true or false:

If (b == true) {
//do something

Doing so adds a bit of overhead in your conditional (assuming the compiler doesn’t optimize it out). Instead, just write:

If (b) {
//do something

Use the following table to see the best use of the Boolean b in a conditional.

Expression Better Alternative
b == true / b != false b
b == false / b != true !b

Of course, in order to maintain code clarity, appropriate naming conventions are crucial. Using appropriate names means that one should be able to deduce the meaning of the expression simply by reading it:

if ( !empty && valueFound ) //Expression is easily understandable by reading it

Another bad practice is using the value of a Boolean indirectly:

if (someBooleanExpression) {
return true; //if true return true...
} else {
return false; //if false return false...

Again, just use it directly:

return someBooleanExpression; //use the value directly

Indirect usage of conditionals makes the code unnecessarily long, slightly slower and shows a lack of a true understanding of how Booleans work (or you weren’t paying attention :) , it happens)

Lastly, if you find that you’ve got a large if, else-if structure checking the value of an integral type, use a switch statement instead. Most importantly, switches increase code readability. Also, they are typically better optimized by the compiler and will be anywhere from much faster to roughly the same speed as a large if, else-if structure. The details of the optimization are the topic of a different discussion.

Short-Circuit Evaluation

Hopefully, if you’re reading this post, you are aware of this concept and can skip over this section. Short circuit evaluation occurs when a Boolean statement’s evaluation stops once the overall value of the Boolean is known.  Short circuit evaluation is typically enabled by short-circuit Boolean operators which differ from standard operators. This is the case with C++ and Java:

Standard operators: &, |

Short-circuit operators: &&, ||

This means that in the following two cases, otherExprs will not be evaluated:

if ( falseExpr && (otherExprs) ) //Always false regardless of value of otherExprs

if ( trueExpr || (otherExprs) ) // Always true regardless of value of otherExprs

If you know how to use these operators well, you can use them to write some pretty powerful conditional statements by deliberately short-circuiting in order to:

1. Avoid handling a null object erroneously:

if ( obj != null && obj.doSomething() )  //this ensures that contains is never called on a null object

2. Avoid expensive operations:

if ( value == lastValue || largeMatrix.contains(value) ) // if we can know that the large matrix contains the value without having to call the contains method, we do not need to make the call and can avoid the expensive operation, yes.. not the best example but you get the point

Regular Boolean operators should be avoided. However, in rare cases, they may prove useful: if a Boolean method has a side-effect that is desired regardless of the outcome of the expression then a regular operation may be useful.

if ( func1WithSideEffects() & func2WithSideEffects() ) //this ensures that both functions are always evaluated

Strategies for Conditionals

Finally, I thought I would outline two general strategies that can be used when writing conditional statements in a program. These aren’t hard and fast rules, so they should not be strictly adhered to in all situations. I’ll call the first strategy clarity.

The clarity strategy is an important strategy to follow, it deals with if blocks that handle numerous cases. It consists of placing the valid/good/expected case first, followed by the invalid/bad/exceptional cases.

if ( (x1 > 0 && x1 < 100) && (x2 > 100 && x2 < 200) ) {
//valid input first
} else {
//invalid input, can check what exactly makes it invalid here, or can use else-ifs instead of else

This makes code more readable and maintainable, and if the common case is the valid one, then performance is better as we do not need to check for all possible invalid scenarios, which in most cases is much larger than the set of valid ones.

This leads into the other strategy I’ll mention: speed. The speed strategy consists of handling the common case first (or fastest case first if its performance is such that it warrants being checked first despite occurring less often). Typically this strategy requires profiling to observe which ordering yields the best performance. Another important aspect is to effectively use the else block. The fact that the code has progressed to the else block means that all of the other expressions evaluated to false. By taking advantage of this fact, you can shift slowly evaluating expressions into the else clause, thus avoiding needing to evaluate them. In general, if you can use an else instead of an else-if based on the pre-conditions resulting from all the expressions evaluating to false, then do so. Use an assert statement instead if you want to ensure the conditions are indeed met.

Altogether, remember that macro-optimization is much more crucial, but by writing better conditionals you can really squeeze out those small performance gains, especially when tight looping is involved. Most importantly, better conditionals greatly improve code readability and maintainability.


The first language debate

July 25, 2009

As a student at the University of Waterloo during its transition from Java to Scheme as a first language to teach, the debate about “what programming language should one learn first?” has been all too familiar to me. This article got me thinking about it again.

In summary, the article states that Scheme is a simple language to learn because it expresses programs using the functional programming paradigm. The syntax has less operators and represents the programs as mathematical functions (lambda calculus) instead forcing you to learn different ways of doing the same thing. While other languages, such as C and Java, have the benefit of practicality, letting you explore and aspire to make the computer do stuff.

With Waterloo’s transition, the most common complaint I get about Scheme is that no-one uses it. And it’s true; I haven’t seen Scheme’s use outside of school. And seeing that some Waterloo students do co-op after their first four months of school, Scheme can seem pretty meaningless when job descriptions ask for Visual Basic, C++, etc. But with my first language being a Java-like language, C#, when I was in Computer Engineering, I do have some bias over my opinion (thanks to Mr. Gates’ donation to the Engineering faculty).

To be honest, I don’t truly know what functional programming and lambda calculus is, but I think the topic is important enough to cram in with my Geography courses (check out CS 442). I barely remember functional programming because I used it about two times while learning Python, such as iterating through a data structure functionally (which is pretty elegant). From my view, Scheme’s syntax is minimalistic and unlike any language I’ve worked with. Scheme deals with more recursion, while avoiding object oriented programming – something I struggled with.

It’s pretty random that I’m in CS right now; I actually avoided programming jobs for my first co-op because I didn’t understand what an object really was. (It’s a box? A recipe? Huh?). Later, I learned programming by playing around with the debugger in Visual Studio – going through the program step by step. The debugger got me over the learning bump others struggled with. I was lucky to figure out the debugger on my own, and I wish educators considered using the debugger when teaching any language.

But if C# wasn’t as practical as it was, I might not be in CS because what really got me into programming was volunteering to write a program to format and merge Excel spreadsheets during my first co-op. Practicality is what got me going into CS, and still motivates me.

Even though I don’t fully understand the pros of Scheme, I will agree with the author of the article: go for the middle ground, Python. It’s used by the University of Toronto. Python’s syntax is minimalistic, it’s easy to setup, and it can be object oriented or functional. Something as mathematical as Scheme would probably detract students like me. People learn better if they apply their knowledge outside of class. After all, school isn’t everything.

(By the way, for the Waterloo-ers, the Math Faculty curriculum for CS isn’t that bad, you get to learn C or Python later on. I’d think that the transition from Scheme to C must be brutal though.)

PS: If you know of any other good developer related RSS feeds other than InfoWorld, a link would be nice =)