0

I have a very simple c++ class defined in foo.cpp:

class Foo
{
    int x;

public:
    Foo()
    {}

    Foo(int _x)
    : x ( _x )
    {}

    int getX() { return x; }

    void print()
    { std::cout << "Foo { " << x << "}" << std::endl; }
};

In trying to wrap it with cython, I create foo.pxd with the following declaration:

cdef extern from "foo.cpp":
    cdef cppclass Foo:
        Foo() except +
        Foo(int) except +
        int x
        int getX()
        void print()

However, on attempting to build this, and cimport it into my pyx source file, it gives me the following compilation error:

Error compiling Cython file:
------------------------------------------------------------
...
    cdef cppclass Foo:
        Foo() except +
        Foo(int) except +
        int x
        int getX()
        void print()
            ^
------------------------------------------------------------

foo.pxd:9:13: Empty declarator

Error compiling Cython file:
------------------------------------------------------------
...
    cdef cppclass Foo:
        Foo() except +
        Foo(int) except +
        int x
        int getX()
        void print()
            ^
------------------------------------------------------------

foo.pxd:9:13: Syntax error in C variable declaration

I was attempting to follow this tutorial, however it doesn't seem to work in my case. Even modifying it such that the Foo::print method takes an integer argument y, and updating foo.pxd to void print(int), I get the same exact error.

What could I be doing wrong, and why am I getting this behavior?

OakenDuck
  • 485
  • 1
  • 6
  • 15
  • I suggest posting your solution as an answer rather than including it in the question. (Yes, you can answer your own question.) – Keith Thompson Jul 24 '21 at 02:51
  • I was aware, I just wasn't sure it warranted it, but I'll do that @KeithThompson – OakenDuck Jul 24 '21 at 06:13
  • I don't think this is quite a duplicate of https://stackoverflow.com/questions/8882649/is-there-a-way-to-wrap-a-structure-that-is-named-like-a-keyword-eg-print, but it's pretty close – DavidW Jul 24 '21 at 09:02

2 Answers2

2

The problem isn't that print is a built-in function. That's fine. You can override the names of built-in functions with no problem.

list = 1  # perfectly valid code; (but may confuse future users)

The problem is that print is a built-in keyword. This is because Cython defaults of Python 2 syntax when reading .pyx (for the moment). To fix this use the language_level=3 compiler directive.

Cython also has the ability to use a different name in Cython to the one that's used in C/C++ to fix this type of name clash. You could use that instead

cdef extern from "foo.cpp":
    cdef cppclass Foo:
        ...
        void cpp_print "print"()

That means that cpp_print in Cython gets translated to print in C++.

DavidW
  • 29,336
  • 6
  • 55
  • 86
  • I was unaware that it defaults to 2.x, and I knew `language_level` existed but I wasn't sure what its function/use was, thank you I'll have to look into that! That's very helpful. – OakenDuck Jul 24 '21 at 16:42
0

The answer is actually quite simple, yet very useful to know. The name of the member itself was the problem, not how I was declaring it in foo.pxd. Given that print is a built-in python function, it seemed to clash with that; changing the name to anything that isn't a built-in method/function/type, or is a keyword should solve the issue. Note that both Python, Cython, and C/C++ keywords/functions can clash with this in the same way.

@DavidW's answer (which I've accepted) clarifies the problem much more concisely. My solution was valid, but the explanation listed was not.

OakenDuck
  • 485
  • 1
  • 6
  • 15