wlav / cppyy

Other
402 stars 41 forks source link

Wrong constructor gets called for mpq_class #92

Open saraedum opened 2 years ago

saraedum commented 2 years ago

The SageMath library has a class to model fractions. When such fractions are passed to mpq_class, the C++ wrapper for fractions from GMP, then strange things happen.

from sage.all import QQ
import cppyy
cppyy.include('gmpxx.h')
cppyy.load_library('libgmpxx')
a = QQ((2, 3))  # the fraction 2/3
a = cppyy.gbl.mpq_class(QQ((2, 3)))
str(a)  # prints 6004799503160661/9007199254740992

I've got some related questions here:

wlav commented 2 years ago

I remember something similar like this one, where a string constructor is selected; can't find that bug report quickly (bit of a mess here with a big conference next week).

I tried to reproduce the above, but the sage on PyPI (https://pypi.org/project/sage/) is probably not the one used above.

There is currently no tracing available. This is in part b/c some functions (mostly operators) are still left to the C++ compiler to figure out, rather than doing the full resolution in cppyy, so there's nothing general to it.

Constructors are also a bit more trouble than ordinary functions b/c construction happens both on the Python and C++ side, has to resolve possible cross-language inheritance, and you can't take a pointer to a constructor on the C++ side, so it always has to be a wrapper call. Overload selection with __overload__ thus doesn't work like it does for other methods. (This is something I need to deal with in the near future within the context of Numba.) In principle, there's enough of a split in Python (allocation, new, and init) that this could be matched a bit mode closely than it currently is.

I don't understand the last question? Maybe if you can point me to how to install sage, I can try and it will become more clear?

saraedum commented 2 years ago

I tried to reproduce the above, but the sage on PyPI (https://pypi.org/project/sage/) is probably not the one used above.

That's correct. You can install sage from conda-forge, it's called sagelib, so the following should work:

mamba create -n cppyy92 sagelib cppyy  # this should pull in GMP as well
conda activate cppyy92
python

I don't understand the last question?

Let me try to rephrase. Let's say that I have a wrapper of a C/C++ object, let's say a Cython class that wraps a GMP rational. Then I would like to convert this always and automatically to the underlying GMP rational in any cppyy calls. To be specific, let's say my Cython class is called Rational and I have a C function void print_rational(mpq_t), then I would like to be able to write print_rational(Rational(...)) without having to perform any explicit conversion by telling Rational that it should always pretend to just be a mpq_t when it enters cppyy.

Does that make more sense?