The Lazy Programmer

August 9, 2009

Dynamic C++ Update

Filed under: C#,Dynamic-Typing — ferruccio @ 2:51 pm
Tags: ,

I’ve been tinkering with my Dynamic C++ project on occasion in order to get it to build successfully under OSX without much luck. Most of it built just fine, but there were a bunch of places where the boost::variant::apply_visitor() function was giving me all sorts of grief.
The original problem was that I was passing an instance of a locally defined struct as the functor argument to apply_visitor(), such as:

unsigned int var::count() const {
    struct count_visitor : public boost::static_visitor<unsigned int> {
        unsigned int operator () (null_t) const { throw exception("invalid .count() operation on $"); }
        unsigned int operator () (int_t) const { throw exception("invalid .count() operation on int"); }
        unsigned int operator () (double_t) const { throw exception("invalid .count() operation on double"); }
        unsigned int operator () (string_t s) const { return s.ps->length(); }
        unsigned int operator () (list_ptr l) const { return l->size(); }
        unsigned int operator () (array_ptr a) const { return a->size(); }
        unsigned int operator () (set_ptr s) const { return s->size(); }
        unsigned int operator () (dict_ptr d) const { return d->size(); }
    };

    return boost::apply_visitor(count_visitor(), _var);
}

This worked fine with Visual C++ 9 but g++ did not like it one bit.  After a bit of research, I discovered that g++ was right and VC++ was letting me get away with non-standard C++. You can declare a struct inside a function, of course, but it cannot have access to any objects in the function scope. Since this was a member function of the var class, it could not have access to the internals of the var class.

No problem, I thought. I’ll just move all these structs into the global scope right before the functions that used them. Except that I had forgotten that all these structs needed access to the internals of the var class, which they had when declared inside a member function. Once outside the member function, the functor code suddenly broke. So, I moved all these structs right into the var class (destroying the locality of reference which I had been so careful to maintain).

Now it compiled fine with VC++, but g++ still gave me a few type errors. Again these all seemed to be caused  by apply_visitor(),  so I decided to drop most of the apply_visitor() calls in favor of switch statements. This would eliminate the few remaining errors but would, much more importantly, put the relevant code close to where it was actually being used.

The main benefit of using apply_visitor() is that if you forget to handle a type, it will generate a compile-time error. I used switch statements whose default block throws an exception. I traded compile-time checking with run-time checking. I can live with that.

Luckily, I had plenty of unit tests in place. I tend to work in increments. Make all necessary changes to a function, compile and test. Repeat until done. There were quite a few times when my changes compiled but failed when I ran the unit test suite. Once I decided to make these changes, it took a couple of hours to make them all and test the results. Everything builds cleanly in Visual Studio and XCode now.

Advertisements

Create a free website or blog at WordPress.com.

%d bloggers like this: