02 April 2007

Maintainable code [for the win]

Books can (and have) been written on this topic, but I'd like to share one of my favorite little constructs. Often times I'll need to change a variable just for the scope of my function (a locking bool or a depth count for instance). It is ALWAYS better to use a temporary class on the stack to do this.

If I set bRecursionLock = true then I have to remember to always set bRecursionLock = false before I return from the function. What if someone other than me (or even me in a few months) has to change that code? What if someone adds a new return and forgets to set bRecursionLock = false? You get a hard-to-track-down bug. Why bother? The simplist C++ construct can take care of this:

class TempLock
{
    bool& m_lock;
public:
    TempLock( bool& lock ) : m_lock( lock ) { m_lock = true; }
    ~TempLock() { m_lock = false; }
};
TempLock lock( bRecursionLock );


We actually had this situation last week. A function needed a temporary class to change a variable on a class instance just in the scope of a function, so I used this construct even though there were no return statements. At the same time, an intern refactored the same function to return all over the place. When both of our changes were merged, the code worked perfectly.

4 comments:

MrTact said...

Or, in D:

void Foo()
{
   if    (!bRecursionLock)
   {
      bRecursionLock = true;
      scope(exit)       bRecursionLock = false;
      // Do stuff here.
   }
}

(Good grief, why does Blogger not support <code> or <blockquote> or even <pre> for heaven's sake?)

scope(exit) works more or less like atexit() does for the process, only with a scope of arbitrary size. Under the hood, it's using a similar implementation to the C++ RAII solution, without the need to explicitly declare the helper class. You can also do scope(failure) or scope(success).

(Yes, I am going all over the Internet posting snarky responses to C++ problems with simpler solutions in D. Because that's what a good zealot does :-)

TimK

Joshua Kriegshauser said...

D seems like an interesting up-and-coming language.

I still have a few problems with it:
1. Compiler maturity
2. Difficulties in porting
3. Library availability
...

Needless to say, most commercial development houses are probably going to avoid adopting it officially, so it's up to hobbyist programmers and independent small companies to promote it, flesh it out and start making it more mainstream.

MrTact said...

You are absolutely right on all counts there. No vendor has shipped a commercial compiler for D, and until someone does, it's going to be perceived as a "hobbyist" language.

Interoperability is a big problem, since D can't directly link to modules written in C++! (The logic is, in order for D to support the C++ object model, it would require the D compiler to effectively also be a C++ compiler, thus eliminating the "clean break" notion.)

Finally, it does need a good standard library. Phobos is decent, covering the basics, but I would categorize it as being equivalent to the C standard lib. The Ares project added to this somewhat. But the exciting development in the world of D libraries is Tango, which I looked at for the first time last night (and was pretty excited by).

Anonymous said...

Good post.