#define ___ // defines three underscores as nothing
This is something I learned on my first programming job (eons ago…) and found useful but underused.
Useful for what? To solve the persistent tension between the robustness of single-exit point and the complexity of using extra state variables and state checking code.
Let me show you what I mean.
Say you write a function that needs to return an element matching some spec or create a new one. There are two ways to code this.
The simple yet multi-exit way:
Element *matchingElement() { for (Element *e in collection) { if ( isMatching(e) ) { // some important code return e; // first exit point } } return newElement(); // second exit point }
The single-exit way:
Element *matchingElement() { bool foundMatch = false; Element *e = getFirstElement(); while (e != nil && !foundMatch) if ( isMatching(e) ) { // some important code foundMatch = true; // setting state variable } e = nextElement(); } return foundMatch ? e : newElement(); // single exit point from function }
Now some of you are wondering why bother with foundMatch; you need to go read Tom Dalling’s Coding Tip explaining the problems with multiple exit points.
Others shudder to see a return statement in the middle of the function; you should remember that more variables mean more code mean more bugs.
So how does the three underscores idiom solve this conundrum? It goes hand in hand with the common convention of 4-space indentation. Together, they allow you to write this:
Element *matchingElement() { for (Element *e in collection) { if (isMatching(e) ) { // some important code ___ ___ ___ return e; } } ___ return newElement(); }
And suddenly both exit points become clear and visible and not so prone to bugs.
The three underscores idiom should be used not only for return statements, but for any jump in the flow of control, like break or continue in a loop:
Element *matchingElement() { for (Element *e in collection) { if ( notEvenClose(e) ) { ___ ___ continue; } if ( isMatching(e) ) { // some important code ___ ___ ___ return e; } } while ( e = nextElement() ); ___ return newElement(); }