[C++-sig] V2: wrapping int/double bug(?)
David Abrahams
david.abrahams at rcn.com
Tue May 14 14:26:56 CEST 2002
----- Original Message -----
From: "Pearu Peterson" <pearu at cens.ioc.ee>
> Yes, there is. As I mentioned in my previous message, the library that I
> am wrapping is a symbolic algebra library where floats are inexact and
> ints are exact numbers, roughly speaking. Trivial example: if I'd used
> only double argument constructor:
>
<snip>
Thanks for the nice explanation. It always helps to understand the domain
my users are operating in.
> > I ask because in general it would seem
> > like a bad idea to implement different semantics for f(4) and f(4.0),
and
> > doubles tend to be able to represent all the values of an integer.
>
> It depends on the application, I guess. In numerical applications
> nobody represents integers by doubles for various reasons (efficiency,
> accuracy, etc).
I understand why you need this distinction in your application, but for
most I think efficiency of int->float conversion is a misplaced concern at
the Python/C++ boundary> I guess that on 64-bit machines an int doesn't fit
in the mantissa of a double.
> I understand this can be feasible for a number of
> applications that hardly deal with numerics or if they do then only with
> floating point numerics. And therefore they don't care if int becomes
> float.
Yeah, it's a pretty common model.
> > > but I don't see how your suggestion would solve
> > > the problem in hand. That is, if a wrapped class A defines methods
> > >
> > > .foo(int)
> > > .foo(float)
> > >
> > > and a class B has both __int__ and __float__ methods, then in Python
> > >
> > > A().foo(B())
> > >
> > > how can you tell which method, __int__ or __float__, should be called
> > when
> > > doing conversion? E.g. take B=int and then take B=float.
> >
> > I assume you mean the cases where B() returns int or float.
>
> No. I mean that B() is an instance of the class B that represents either
> int or float
Oh, OK. But that case is easy.
> , or can be transformed to one.
As long as it can't be transformed into both, also easy. Even then, it's
easy because you just signal an ambiguity.
> Take, for example, B is
> Rational, or an arbitrary precision number.
>
> > That's easy: Python int would correspond most-closely to C++ int, and
> > Python float would correspond most-closely to C++ double.
>
> I agree. But BPL does not seem to agree with that ;-)
Yes; think of it as your next project ;-)
> > > In order to do it properly, at some point the responsible mechanism
in
> > BPL
> > > should check whether an instance B() has more an "int nature" or more
a
> > > "float nature". This is easy, in principle, if B is int or float (or
> > > a subclass of int or float) but not obvious at all if B is, for
example,
> > > str
> >
> > neither the built-in function str() nor built-in strings have __int__
or
> > __float__ methods, so in that case there would be no match at all.
>
> And yet
>
> >>> float("2.3")
> 2.2999999999999998
> >>> int("2")
> 2
Yes, that's the float/int types doing the work.
> so I didn't look in to details of how these numbers are constructed.
> str was a bad example. Forget it.
Done.
> > > or an user defined class that defines both __int__ and __float__
> > > methods.
> >
> > In that case I would consider the call ambiguous.
>
> Which is exactly the case for Python int and float:
>
> >>> int.__int__
> <slot wrapper '__int__' of 'int' objects>
> >>> int.__float__
> <slot wrapper '__float__' of 'int' objects>
> >>> float.__float__
> <slot wrapper '__float__' of 'float' objects>
> >>> float.__int__
> <slot wrapper '__int__' of 'float' objects>
When converting to integral argument types, I would use a rule which gave
priority to classes derived from Python int as arguments.
> > > And that approach is unacceptable because it would mean that all
methods
> > > (that I would like to use from Python) of A, must be re-wrapped as
> > > well.
> >
> > No, I don't think so. You only need to wrap them once in
> > class_<A,A_wrapper>. It's only constructors which need to be duplicated
in
> > A_wrapper.
>
> I tried that, but it didn't work out.
<snip>
> It is not clear to me how to include
>
> class numeric_wrapper: public GiNaC::numeric {
> numeric_wrapper(PyObject*);
> }
You need an extra PyObject* argument in the constructor. The first one is
the self pointer, and you can ignore it if you like.
> into this tree. If I remember correctly then
>
> .add(boost::python::class_<GiNaC::numeric,
> boost::python::bases<GiNaC::basic, numeric_wrapper> >("numeric")
> .def_init(boost::python::args<const numeric &>())
> ...
>
> didn't work because the constructor of numeric_wrapper was never called -
Well, it also doesn't work because numeric_wrapper is not a base of
numeric, but a derived class!
You should follow the formula I described above:
.add(boost::python::class_<GinaC::numeric, GiNaC::numeric_wrapper
>("numeric")
.def_init(boost::python::args<PyObject*>())
See the documentation for class.hpp if you need an explanation of what's
happening here.
> I meant that I ended up with implementing methods like
>
> basic_add_basic
> basic_add_pyobj
> basic_add_ex
> basic_add_numeric
> ex_add_basic
> ex_add_pyobj
> ex_add_ex
> ex_add_numeric
> numeric_add_basic /* Though numeric is derived from basic, its
> numeric_add_numeric arithmetics is done in a different route */
> numeric_add_ex
> numeric_add_py
>
> Similarly for mul,div,sub,pow,etc.
Yikes. I am planning to implement simplified operator exposure this week; I
hope that helps you out.
> And then I noticed that the size of the wrapper was becoming close to the
> size of the library itself, which stopped me and made me doubt if
> this approach is a good one.
Yeah, if you have to mess around with PyObject*, the library isn't doing
you much good is it?
> > > Now, the question is whether it is possible to introduce additional
> > > constructors to library classes without deriving a new class for
that?
> < snip >
> > > What do you think? Would the above be possible in principle?
> >
> > In principle. my_A_init has to build and install a Holder; it can't
just
> > return a new A copy... at least, that's the way the library works now.
>
> Thanks for the hint. I'll try to figure out that if nothing else works.
>
> still-not-convinced-that-bpl-cannot-wrap-real-libraries'ly yours
Me neither, fortunately ;-)
-Dave
More information about the Cplusplus-sig
mailing list