Wednesday, March 18, 2009

How to assert and still have your compiler happy.

I've been questioning whether to post this or not, since may be there are a more than a dozen ways to solve this problem and I might just be overcomplicating a simple meter. In the end I decided to ask and expose my ignorance because that's the only way you can learn =).

Recently, relatively of course, a new problem has arose in the KDevelop mailing list. In essence the problem lies in code like this:

bool check = foo.doSomething();
Q_ASSERT( check )

or

bool check = foo.property()
foo.doSomething()
Q_ASSERT( check == foo.property() )
You get the idea.

Which is better than what it used to be:

Q_ASSERT( foo.doSomething() )

very effectively making the project not work on release mode =D.

However the first statement, while correct, creates noise in the form of compiler warnings about unused variables. A solution that somebody proposed was just:

#ifndef QT_NO_DEBUG
bool check =
#endif
foo.doSomething();
#ifndef QT_NO_DEBUG
Q_ASSERT( check )
#endif

or
#ifndef QT_NO_DEBUG
bool check = foo.property()
#endif
foo.doSomething()
#ifndef QT_NO_DEBUG
Q_ASSERT( check == foo.property() )
#endif

Legibility suffered so it was reverted, at least it was asked to be reverted, not sure if the reversion was made.
As a solution I proposed just wrapping the variables in a Q_UNUSED macro but I got in response that that's the wrong message in the second case since they are used, only not in release mode. So the question is, how to solve the problem?.
While I want to hear what you can come up with here's a thought:
For the first case we could create a new assert, name it K_ASSERT for originality sake, and have it like this:
K_ASSERT( bool check, foo.doSomething();, Q_ASSERT(check) )

which might be expanded as:
bool check = foo.doSomething();
Q_ASSERT(check)

on debug mode and just:
foo.doSomething();

on release mode.
And for the second case we would need a macro which allows us to run code only in debug mode:

K_DEBUG_MODE( bool check = foo.property(); )
foo.doSomething();
Q_ASSERT( check == foo.property() )

which, if I'm correct, would be expanded as:
bool check = foo.property();
foo.doSomething();
Q_ASSERT( check == foo.property() )

on debug mode and
foo.doSomething();

On release mode.

All in all I need that in essence what's needed is a macro which let you separate release and debug contexts allowing you to execute code in debug but not in release mode.

After thinking it further I believe that no K_ASSERT is needed but K_DEBUG_MODE can be used instead and then the first case might be written as:

K_DEBUG_MODE(bool check = foo.doSomething(); Q_ASSERT(check) )

As a disclaimer I haven't played enough with Macros to tell whether it'll work or not but what you guys think? am I taking the long route?, is there something already thought for these cases?.