Archive for July, 2007

No matter how much I wash, my hands are unclean

Monday, July 9th, 2007

Here’s a C++ issue that’s been stumping me all morning. I’ve got a compiler error in a header file that states that a particular symbol is not declared within the current scope. I’ve been able to figure out is that the compiler is right - I certainly cannot find any way that this symbol is available anywhere that any compiler would be able to find it. A mitigating factor is that the missing symbol is within the declaration of a template.

Grepping across all files in the project, I can find the symbol repeated in many files as a local static constant.

static const char kValueDescription[] = "Writes Null Files";

This same definition appears in many files, each file has its own unique string. So these definitions of my missing symbol are available only after the inclusion of my header file. Just to test, I moved the include of the header from the top of the cpp file to a point below the alleged definition of my missing symbol: the missing symbol error goes away. It just seems plain wrong to require something to be defined prior to inclusion of a header file. Header files should be self contained: it should forward declare classes it can’t know details about or include other headers to get the declarations that it needs.

So here’s what I think is going on: the code is banking on the assumption that the compiler will blindly treat the template as if it were a macro. The original author wanted the compiler to not process the template until it is actually instantiated (coincidentally immediately after the the declaration/definition of the missing symbol). In my case, the compiler is not cooperating and as far as the source file is concerned, compiling the template prematurely.

I know that the GNU C++ compiler has had a bug in the past that where templates were instantiated prematurely. I’m not yet sure if this is an instance of this problem. I’ve seen the premature template instantiation problem manifest as an unlawful symbol redefinition, not a missing symbol. The question is, should a compiler fully check a template prior to instantiation? I would say “yes”, unfortunately, this code says, “no.”

I need to find a solution. Either I have to make the new location of the include permanent, an option I find distasteful, or I need to find a way to forward declare the static const char array in the header file. Unfortunately, forward declarations are for classes, not data items. How do you forward declare data?

So I am forced to be unclean. I’ve moved the header inclusion from the top of the file where it belongs down into the middle of the source file. This makes me ill with foreboding that there will be more trouble in the future from this.

The return of the language lawyer

Thursday, July 5th, 2007

Now that the nursery work is virtually complete for me, I can reallocate that part of my brain to my real career. Today, I reconnected with a part of my past: I woke the C++ language lawyer in me. I haven’t seen him in ten years.

I have this big pile of C++ code in front of me representing a development project from the late nineties. It is a wild mixture of coding styles embracing complex preprocessor systems for class declarations simulating templates, real templates, multiple inheritance, private inheritance, a roll-it-your-own runtime type identification system, all wrapped around a chewy Microsoft COM API. There are several hundred classes in several hundred files riddled with conditional compilation directives switching on everything from Win16 to Solaris. Few declarations are not wrapped in defines while most types are typedef’d or macro’d within an inch of their lives. Oh yeah, it’s got some threading, too.

While a branch of this code allegedly compiles on Linux under GNU 3.x, I am trying to use version 4.1.x to compile it. I am told that the 4.x GNU compilers are significantly pickier than the version 3x compilers. The actual code hasn’t been touched in at least four years. Honestly, it looks as if the team of programmers assigned to this code were unexpectedly escorted from the building during a mass layoff. Several files look to be half way through a refactoring effort. I find undeclared variables, misspelled enumerations, missing and ambiguous scoping, unused parameters and many other problems.

My task is to make it all compile because it must be drafted into use. I’m all for recycling and have embraced the object oriented code reuse credo since 1988, but I am taken aback by the complexity of this task. It may be that the original coders were too clever several times over. There are some nether regions of the C++ standard that are terrifyingly beautiful with fractal complexity: but I would think twice about using them in production code. I must say that the coder’s intent is rendered rather opaque by the language.

I’ve been here before. However, I was on the other side: I have written opaque code while enthralled with the brilliant yet twisted beauty of the underlying structure. I wrote it during the same era that this code originates. No documentation would ever be needed for it, it’s so obvious, “a child could do it”.

With age comes a modicum of wisdom. I know where these people and, indeed, I myself, have gone wrong in the past. Code must be written knowing that the high priest will pass on. It is time for me to pay for the follies of my youth. I walk to my task of atonement willingly and with my eyes open. When my delayed penance is served and I am free once more, I will return to Python coding with an eye for those who will come after me.