My Kingdom for a C+ Compiler!

January 23rd, 2007

Let the ranting begin…

This is probably the eighth time I’ve written a vector.h. Why so many rewrites, you ask? Because it’s taken that long for me to divorce myself from C++’s second plus. A brief history of our rocky little relationship, as recorded in the revision logs of my math utility files (and written in third-person, because that amuses me), follows:

  • Revision One: Phill meets C, who introduces him to her sister C++. He is immediately smitten with her charming operators and her tight, expressive form. He goes home and does what he always does when he learns a new language. He sees how cool of a vector.h he can put together. He thinks to himself:

    template< unsigned int n >
    struct vector
    {
        /* some constructors */
        /* some assignment operators */
        /* lots of overloaded math operators */
    }     
    template< unsigned int n >  
    float length( const vector< n > &v0 );   
    //and so on
    

    The sudden realization that he’s just written vector2, vector3 and vector4 all at once is too much to handle…he goes and takes a nap.

  • Revision Two: Phill likes the way HLSL looks. He wanders off into vector.h and starts typing stuff to make the C++ code look more like that. Constructors are constructed. Operators are operated on. Goodness abounds. Phill is so happy he sets his desktop wallpaper to a picture of a beach, codes some more, exhausts himself and takes another nap.

    That night he dreams of vector::vector( float f ) which initializes each of the vector’s components to the value of f and allows pretty code like vector3 v = 0.

  • Revision Three: Phill wakes up energized and ready to code. He starts writing…a program. Because he hates to reinvent the wheel (except where vector.h is concerned) he brings in some existing code. Said existing code happens to be written in C (whom Phill still talks to every now and then), and uses a typedef float vec3_t[3] for its vectors.

    Phill is getting rather sick of typing vector3( v[0], v[1], v[2] ) every time he needs to initialize a vector quantity. He quickly puts together some conversion operators to translate between vec3_t and vector3.

    The astute reader will note that the seeds of a really nasty bug have just been sown…

  • Revision Four: Phill runs the program and it takes ages to load. Confused, Phill pulls out a profiler and tracks down the offending code. It seems that the vector::vector( void ) which initializes the vector to zero is making stl::vector’s various resizing operations take ages to complete. Irritated, Phill rips out the offending constructor; he replaces it with an empty one.

    Program behavior has just been altered in a fundamental way. Let the hunting for uninitialized variable bugs begin…

    Of course, debug builds are still unbearably slow - but it’s easier to blame it on the STL than on the shiny templated vector class. And could someone please explain why the compiler won’t allow the vector type into a union…the default constructor is empty…I mean come on!

    The magic is wearing off; the tropical beach has been banished from the desktop.

  • Revision Five: Sick of typing vector all the time, Phill renames it to vec. Find and replace vector => vec. Whoops. Find and replace std::vec => std::vector. Fix the files that started with using namespace std by hand.

    Phill reminisces about good times had, and wonders why C++ doesn’t make him smile any more.

  • Revision Six: A rarely-executed code branch suddenly reappears like an unwanted in-law coming to visit. It executes. The program crashes in vec::vec( const float* ). One line up the call stack we find the line vec v = 0. Phill is confused until it hits him that a literal 0 casts more easily to a float* than to a float.

    He dies a little on the inside, but he’s determined to make this work. He goes through the code and replaces = 0 with = 0.0F.

    The magic is gone.

  • Revision Seven: More confusion. This time it’s in overloaded operator land. It seems the compiler can’t choose between two equally good conversions. Of course, Phill doesn’t expect the compiler to understand that it doesn’t matter which conversion it uses. He just wishes C++ would let him tell it.

    Phill’s thinking of just calling the whole thing off. It’s just that he doesn’t want to abandon the new program (even though it’s talking back an awful lot these days).

  • Revision Eight: Phill’s finally had it. The impossible battles with overloaded functions, the slow debug builds, the ceaceless whining from the compiler…

    Phill trashes vector.h and copies in his original C version. He then renames the math functions to things like operator + because that’s pretty much the only thing that didn’t break or become annoying.

    The constructors become a set of functions: vecNc which takes a set of literal float values (and a few unambiguous overloads involving vectors of fewer elements) and returns a vecN. vec::vec( float* ) becomes vecNv.

    It’s a painful transition but it works and for the first time the fuzzy sense of magic has been replaced with a concrete understanding that this line of code does this. The code size drops noticably as dozens of types that never needed constructors (but got them anyway because they had a vec in them) start to compile into something sane again. It turns out that the STL was only responsible for about 25% of the debug-mode slowdown. The rest was all abusive constructors doing evil things.

    Epilogue: Phill and C++ have since gone their separate ways, deciding that it would be better if they were just friends.

And don’t even get me started on the awful inbred mess of of a multiple inheritance implementation that C++ seems to be stuck with. Or all of the countless portability issues. Or the annoying…er…</rant>

The really irritating part is that in any serious project you pretty much can’t just take one plus and not the other. You can make all the rules you want, but if you’re compiling with a full C++ compiler someone will eventually come along and put a constructor in some little utility type that’s used everywhere, or use multiple inheritance, or make obscenely complex templates that nobody can figure out (often not even the compiler). Sooner or later you’ll even see a dynamic_cast in there. And then there’s nothing you can do but rename all the .cpp files to .c and fix the compiler spam.

I’d kill for some compiler switches, or even easy-to-grep-for #pragma directives, to turn off some of the more troublesome C++ features. Seriously, my kingdom for a C+ compiler…

2 Responses to “My Kingdom for a C+ Compiler!”

  1. Jordan Says:

    Ahh the sordid, unsavoury world of coding… have you checked for STD’s (symantically transmitted diseases)?

  2. Chris Says:

    DJ Phil ftw

Sorry, comments are closed for this article.