Statically Typed

because Hindley-Milner rocks

Swig, Python, Cross-Language Polymorphism and C++ Exception Handling


Back to cross-language interoperability I go!  And with me I’m bringing my dear old friend with me, SWIG.

I love SWIG and I’m not afraid to admit it.  It makes my life much, much easier.  I don’t need to hand-roll extensions to my target language every time I want to get something done.  However, many die-hard C++ library freaks out there would be quick to point out that there’s a nifty little library that has been designed with Python in mind (see: Boost.Python.)  But, and you knew there was a but, when you’re now allowed Boost SWIG is there for ya.

Our problem is simple.  We’d like to take an abstract C++ base class, extend it in Python, and have the underlying C++ libraries treat that Python class as it would any C++ class which inherited from the base class.  That means, if the Python code raises an exception, that exception propagates up the C++ stack until it is caught.  Specifically, we’d like to be able to throw exceptions that we’ve defined in C++ and have the C++ catch it as those exception classes.  This is critical.

So far the good news is that SWIG::directors handle the cross-language polymorphism fairly well.  I’ve written a simple set of C++ classes to test out the functionality.

class Alarm : public std::exception{
public:

    const char* msg(){ return "Gimme five more minutes"; }
};

struct Foo{
    Foo(){}
    virtual ~Foo(){}

    virtual int  getValue() =0;
    virtual void throw(){ throw Alarm(); }
};

class Bar{
public:

    Bar(Foo *_foo) : m_Foo(_foo){}

    int  getValue(){ return m_Foo->getValue(); }
    void report(){
        try{
            m_Foo->throw();
        }
        catch(Alarm &ex){
            std::cout << "Wake up!" << std::endl << ex.msg();
        }
        catch(std::exception &ex)
            std::cout << ex.what();
        }
        catch(...){
            std::cout << "What just happened?";
        }
    }
private:

    Foo *m_Foo;
};

This sets the stage for us to wrap things up nicely with the *.i file SWIG requires.  It looks like this:

%module(directors="1") foo
%feature("director");
%{
#include "Foo.h"
%}
%include "Foo.h"

I’ve enabled directors for all classes in this example knowing that only Foo contains virtual methods.  At the Python level I define two classes:

class PassFoo(Foo):
    def __init__(self):
        Foo.__init__(self)
    def getValue(self):
        return 4

class FailFoo(Foo):
    def __init__(self):
        Foo.__init__(self)
    def getValue(self):
        return 5
    def throw(self):
        raise Alarm

The different between these two classes, aside from their names, is the location of where within the stack the exception Alarm is thrown.  PassFoo keeps the logic completely in C++ while FailFoo attempts to throw the exception on the Python side.

The outcome?  When Bar is initialized with PassFoo, the output message from Bar::report reads like I was back in school again.  When Bar is initialized with FailFoo, something entirely different happens in the call to Bar::report.  First the SWIG director intercepts the exception, handles it besides the scenes, and passes a Swig::DirectorMethodException to the C++ code.  Bar::report winds up asking “What just happened?”

So there you have it.  Part way through my journey and I am only able to handle exceptions one way, C++ to Python.  I’ve put a question up on Stack Overflow and had a poster answer with a very good idea.  We’ll try things out with his method but I’m not giving up on SWIG.  I know someone, somewhere thought this out.  All I have to do is find it in the documentation.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Information

This entry was posted on May 25, 2010 by in C++, Python.
%d bloggers like this: