Tuesday, June 24, 2014

Lambdas instead of #define?

Recently I was running into this kind of code:
#if ONLY_WHEN_TRACKING_DOWN_BUG
#define DUMPINFO(NameStatDumpInfo(NameStat)
#else
#define DUMPINFO(NameStat)  /* Nothing */

void FunctionCalledALot()
{
 [...]
 string InfoName;
 int InfoStat;
 GetInfo(InfoNameInfoStat);
 DUMPINFO(InfoNameInfoStat);
 [...]
}

Which got my OCD up & running, as InfoName and InfoStat might not get removed (since the compiler might not figure out that GetInfo() has no side effects).

The typical way to solve this is to add the enclosing #define:

void FunctionCalledALot()
{
 [...]
#if ONLY_WHEN_TRACKING_DOWN_BUG
 string InfoName;
 int InfoStat;
 GetInfo(InfoNameInfoStat);
 DUMPINFO(InfoNameInfoStat);
#endif // #ONLY_WHEN_TRACKING_DOWN_BUG
 [...]
}

The problems with this fix are:
a) DUMPINFO might have more conditions (like depending on a console variable)
b) Code rots: There might not be enough people enabling ONLY_WHEN_TRACKING_DOWN_BUG, which will cause the code to never get compiled, so changes to signatures or types will cause errors for the poor soul who tries to use it.

I was fiddling with this kind of solution, which I hope would fix those issues:
void FunctionCalledALot()
{
 [...]
 auto DebugInfoLambda = [&]()
 {
  string InfoName;
  int InfoStat;
  GetInfo(InfoNameInfoStat);
  return std::make_tuple(InfoNameInfoStat);
 };
 DUMPINFO(DebugInfoLambda);
 [...]
}
I'm sure it has its drawbacks, but I think it solves the code rot issue, and the dead-code optimization issue too. So far the disassembly seems reasonable...

No comments: