MWB
MWB

Reputation: 12587

Is overloading broken in cppclass Cython/C++ definitions?

Cython documentation shows how to declare existing C++ classes with overloaded methods.

However, if I define my own cppclass with an overloaded method ...

cdef cppclass point:
    float x, y

    point():
        this.x = 0
        this.y = 0

    float sum():
        return this.x + this.y

    float sum(int z): # COMPILE ERROR
        return this.x + this.y + z

... I get

Function signature does not match previous declaration

Overloading the constructor gives the same error there:

cdef cppclass point:
    float x, y

    point():
        this.x = 0
        this.y = 0

    point(float X, float Y): # COMPILE ERROR
        this.x = X
        this.y = Y

    float sum():
        return this.x + this.y

Am I doing this incorrectly, or is this feature missing?

Update: Default arguments seem to be unusable too:

cdef cppclass point:
    float x, y

    point(float X=0, float Y=0):
        this.x = X
        this.y = Y

    float sum():
        return this.x + this.y

cdef float use_point():
    cdef point p
    p = point(1, 2)
    return p.sum()

... passes Cython, but gets tripped up by the C++ compiler ("wrong number of arguments")

Upvotes: 10

Views: 2683

Answers (2)

DavidW
DavidW

Reputation: 30917

As I said in a comment: this clearly is a bug/unsupported feature, and so it's probably much more useful to report it on the Cython issues list on github than post it here.

However, if you're interested in a hacky short-term workround then the following works:

    float sum(...):
        return this.x + this.y

    float sum2 "sum"(int z):
        return this.x + this.y + z

# A test function to prove it
def test():
    cdef point pt
    a = pt.sum()
    b = pt.sum(3)

    return a,b # returns (0.0, 3.0)

This uses 2 tricks

  1. Cython lets you specify an "actual" name for the function by putting it in quotes. Thus float sum2 "sum"(int z): ends up calling the function sum, but it tricks Cython so that it doesn't register than you've reused the same name. The automatic C++ type deduction will work correctly though.

  2. ... (i.e. C varargs) will match anything but it given the lowest priority by the C++ type deduction mechanism. Therefore sum(3) picks sum(int) ahead of sum(...). This also stops Cython thinking too hard about the types and leaves it up to C++ (as desired). The downside is that it won't tell you if you pass a huge nonsensical list of arguments but will just silently call the (...) version.

This hack doesn't work for constructors, and doesn't look easy to make work for constructors.

Upvotes: 9

Czarek Tomczak
Czarek Tomczak

Reputation: 20675

The page you reference in its first part shows examples of exposing interfaces to existing C++ classes. In such case overloaded methods are allowed. I do not think overloading is allowed when implementing classes in Cython. The second part of the page shows how to implement wrappers - Cython classes that wrap C++ classes. Take a look at the example:

cdef class PyRectangle:
    cdef Rectangle c_rect      # hold a C++ instance which we're wrapping
    def __cinit__(self, int x0, int y0, int x1, int y1):
        self.c_rect = Rectangle(x0, y0, x1, y1)
    def get_area(self):
        return self.c_rect.getArea()
    def get_size(self):
        cdef int width, height
        self.c_rect.getSize(&width, &height)
        return width, height
    def move(self, dx, dy):
        self.c_rect.move(dx, dy)

Constructor is named __cinit__. It works similary as in Python. Cython syntax is like in Python. I don't think you can name your constructor same as class name. You didn't provide __init__ nor __cinit__, thus the default constructor expects no arguments.

Upvotes: 1

Related Questions