There is another aspect to my coding style which gets a lot more questions, and that is because it is more than just simple formatting: I write my code specifically to avoid break statements, continue statements, and nested returns. As an example, a double nested loop in my code will resemble:
boolean closed = false;
for (int i=0; !closed && i < fooList.size(); ++i)
{
List<Bar> barList = foolist.get(i).getBarList();
for (int j=0; !closed && j < barList.size(); ++j)
{
closed = barList.get(j).isClosed();
}
}
return closed;
Colleagues reviewing my code often ask why I don't just use the nested return such as:
for (Foo foo : fooList)
{
for (Bar bar : foo.getBarList())
{
if (bar.isClosed())
{
return true;
}
}
}
return false;
This is my answer:
The looping style I use is related to what I learned in one of my graduate-level courses in Computer Engineering when we studied formal proofs of computer programs. I happen to be very mathematically minded and even got a minor in Mathematics as an undergrad, so this particular subject appealed to me. I was also curious how IBM had done some significant development with software validation via formal proofs and no testing and found the results to be at least as high in quality (fewer bugs) as software developed with testing.
Formally proving the correctness of a loop requires stating the invariant of that loop and the condition of the loop. The way I write the condition in the for loop, the invariant and condition can be easily determined by examination. In this case the outer loop invariant is i <= fooList.size() and the condition is as written: !closed && i < fooList.size(). The inner loop is similar.
Since the nested return is logically equivalent, the invariants and conditions are the same, but determining them from examination is extremely difficult. I do not expect anyone to formally prove my loop, but if desired it could be. For myself, I find it easier to validate my style when reviewing code since I tend to think more mathematically.
That is how I got to writing my loops this way. After I had been doing this a short while, I discovered a particular advantage that is even more appealing to me: the single exit point. By having a single exit point, I have a single clear location where I can set a breakpoint or insert a log statement when debugging. I also have an obvious variable to watch (closed in this case). I also have a clear delineation for the beginning and ending of a try block in the event that an exception needs to be caught. This has led me to write my if statements without nested returns as well. All in all, it feels more disciplined to me.
Since this style has paid such dividends to me over the years, I continue to use it. That’s why you don’t find nested return, break, or continue statements in my code. I don’t usually mind if others use them — unless I see a continue statement with a label then I do complain rather loudly.
No comments:
Post a Comment