Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cython syntax for declaring class hierarchies that have aliases

Tags:

c++

python

cython

Here is an abstract base class and a concrete subclass, which I would like to expose to Python via Cython:

class NodeDistance {

protected:
    const Graph& G;

public:
    NodeDistance(const Graph& G);
    virtual ~NodeDistance();
    virtual void preprocess() = 0;
    virtual double distance(node u, node v) = 0;
};


class NeighborhoodDistance: public NetworKit::NodeDistance {

public:
    NeighborhoodDistance(const Graph& G);
    virtual ~NeighborhoodDistance();
    virtual void preprocess();
    virtual double distance(node u, node v);
};

This is my first attempt at declaring the interface of the classes for Cython. To avoid naming conflicts between the cppclasses and the Python wrapper classes, I declare every Class as _Class, followed by its proper name "Namespace::Class".

cdef extern from "../cpp/distmeasures/NodeDistance.h":
    cdef cppclass _NodeDistance "NetworKit::NodeDistance":
        _NodeDistance(_Graph G) except +
        void preprocess() except +
        double distance(node, node) except +


cdef extern from "../cpp/distmeasures/NeighborhoodDistance.h":
    cdef cppclass _NeighborhoodDistance(_NodeDistance) "NetworKit::NeighborhoodDistance":
        _NeighborhoodDistance(_Graph G) except +
        void preprocess() except +
        double distance(node, node) except +

But now I get a syntax error when trying to express that _NeighborhoodDistance is a subclass of _NodeDistance. What did I do wrong?

Error compiling Cython file:
------------------------------------------------------------
...
        void preprocess() except +
        double distance(node, node) except +


cdef extern from "../cpp/distmeasures/NeighborhoodDistance.h":
    cdef cppclass _NeighborhoodDistance(_NodeDistance) "NetworKit::NeighborhoodDistance":
                                                   ^
------------------------------------------------------------

_NetworKit.pyx:1698:52: Syntax error in C++ class definition
like image 995
clstaudt Avatar asked May 01 '14 14:05

clstaudt


1 Answers

I don't think you can even express the combination of base class and renaming in Cython 0.20.1. You can either not rename the classes and specify the namespace in the cdef extern from:

# C++ classes shown at the end
cdef extern from "example.hpp" namespace "example":
    cdef cppclass Base:
        void some_method() except +

    cdef cppclass Derived(Base):
        void some_method() except +

... or not specify the inheritance:

cdef extern from "example.hpp" namespace "example":
    cdef cppclass Base "example::Base":
        void some_method() except +

    cdef cppclass Derived "example::Derived":
        void some_method() except +

Either way, Cython doesn't seem to understand C++ inheritance fully, and you need an explicit cast:

def test():
    cdef Derived d
    cdef Base *p = <Base *>&d
    p.some_method()

This is ugly because the cast effectively turns off typechecking in C++, but with care it can be used safely. (There are other circumstances where Cython's typechecking requires casts that are not necessary in C/C++, which is quite unfortunate.)

For reference, here are the classes I used:

// example.hpp
#include <cstdio>

namespace example {
    struct Base {
        virtual void some_method() = 0;
        virtual ~Base() = 0;
    };

    struct Derived {
        virtual void some_method()
        {
            std::puts("Hello!");
        }
        ~Derived()
        {
        }
    };
}
like image 80
Fred Foo Avatar answered Nov 09 '22 14:11

Fred Foo