Statically Typed

because Hindley-Milner rocks

Swig, Python, and C++ exceptions, part 4


Addressing Abstract C++ Classes

Last post I was discussing using the %notabstract Swig preprocessor instruction on my abstract C++ class.  While Swig was able to create the Foo_wrap.cxx file, gcc was not able to compile it into a Foo_wrap.o file. Removing both the %notabstract and the -classic compile flag to Swig solved the issue.  Why I had been blindly following the examples online instead of using just a bit of thought is beyond me.  I’ve come down on others for copy+paste without understanding yet here I was doing the same thing.

In the “new” style Python classes, a wrapped C++ abstract class contains a Python constructor.  However, if that class isn’t extended in Python with all of it’s virtual methods implemented, the Python code throws an error indicating an attempt to instantiate an abstract class.  It’s pure genius.  Thanks Swig folks.

C++ Exception Woes

Before I converted the code over to using the “new” Python class style I played around with tracing the exceptions through the stack.  This forced me to start looking at some of the deeper issues I faced with exceptions.  Primarily it shed light on how Swig inserted code into the iterop layer and why exceptions were causing stack corruptions.

So let me rephrase the goals we’re trying to achieve before moving forward with this discussion.  I need to add another requirement that has arisen from my experimentation:

  1. Pass a C++ exception originating from the Python stack up the C++ stack.
  2. Pass a Python exception originating from the Python stack up the C++ stack as a C++ exception.
  3. Allow the C++ stack to catch the C++ exception if it contains a try-catch block. (*new*)
  4. Propagate a Python exception originating from the C++ code as a Python exception up the Python stack.

And here is how I’ve tried to address them:

  1. Created the C++ ExceptionFactory class to my project and wrapped it with Python.
  2. Added the %feature( “director:exception”) Swig preprocessor instruction.
  3. Oops…
  4. Added the %exception Swig preprocessor instruction.

You might ask why I’ve decided to add the third item to the aforementioned list of requirements.  The assumption that the Python stack shouldn’t be concerned with the inner workings of the Bar::report() method seems at first glance like a valid assumption.  And normally, you’d be right.

Unfortunately, since the %exception preprocessor instruction as I used it is a global instruction, it will force itself into ever nook and cranny where an exception could potentially happen.  And therein lies the problem.  When the pointer to Foo is called to throw an exception within the Bar::report() method, Swig takes over and attempts to catch it.  This circumvents not only the try-catch blocks but also seemingly the entire C++ stack.  The expected result of catching an Alarm type exception of “Wake up! Gimme five more minutes.” is replaced by “lk923 48h6t#$” or “di9283 48!#% j94@#(*&” or anything that happens to lie at some random memory address.  What’s more, a Python exception is raised corresponding to the type declared in the %exception preprocessor instruction!

The Fix

The %exception preprocessor instruction is very flexible.  It can be constrained to a single class or even a method of a class, thereby allowing large customizations with several declarations.  Attaching it to only one class I create elsewhere will free both Foo, Bar, and the ExceptionFactory classes from it’s grips.

My first attempt to combine the C++-Python exception handling logic used an empty class (nothing but a constructor and virtual destructor) to attach to %exception.  Then I tried to inherit from that class in Python.  It looked like this:

struct ExceptionCatcher{
    ExceptionCatcher(){}
    virtual ~ExceptionCatcher(){}
};

and on the Python side:

class FirstAttempt(ExceptionCatcher):
   def __init__(self):
      ExceptionCatcher.__init__(self)
   def doesItWork(self):
      excFac = ExceptionFactory()
      excFac.throwAlarm()

My FirstAttempt::doesItWork quickly answered the question, no.  A C++ exception was thrown but the Python stack crashed.  I can’t inherit the C++ exception handling logic at the Python end but from the documentation online it appears that I can inherit it at the C++ end.

Tomorrow, when I go into work, this is exactly what I’ll try to do.  I’ll create what essentially are implementations of the Decorator pattern with inheritance.

Advertisements

2 comments on “Swig, Python, and C++ exceptions, part 4

  1. កូនផ្សោត
    March 16, 2011

    Hello,

    I’m a new swig user, I started last fews day.

    I do have some question:

    I used cmake to generate swig with this example :

    # This example shows how to use python
    # Currently these languages have been tested:
    # perl tcl ruby php4 pike

    FIND_PACKAGE(SWIG REQUIRED)
    INCLUDE(${SWIG_USE_FILE})

    FIND_PACKAGE(PythonLibs)
    INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})

    INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

    SET(CMAKE_SWIG_FLAGS “”)

    SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES CPLUSPLUS ON)
    SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES SWIG_FLAGS “-includeall”)
    SWIG_ADD_MODULE(example python
    example.i example.cxx)
    SWIG_LINK_LIBRARIES(example ${PYTHON_LIBRARIES})

    But I have some error messages :

    Unable to find ‘cstdio’
    Unable to find ‘iostream’
    Unable to find ‘fstream’
    ….

    How can I do to us this kind of library in c++

    Thanks in advance. Keep waiting for your help

    • owreese
      March 16, 2011

      It looks like it can’t figure out where to link to your standard libraries. Have you set up your PATH environment variable correctly? This looks like one of those things where I’d really need to be at your computer to help you. I wish I could give more.

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 June 6, 2010 by in C++, Python.
%d bloggers like this: