in reply to Re: Overload '+=' with XSub
in thread Overload '+=' with XSub

Anno, that seems to me to be a reasonable guess .... but I'm looking at a '+=' overload XSub that neither increments the refcount nor (afaict) returns anything ... and I'm wondering "how the hell does that work ?". It's from the GMP module - which is not to be found on CPAN. (It ships with the gmp source - in the demos/perl folder.) I don't know if it's going to help the discussion, but here's that XSub:
void overload_addeq (x, y, o) mpz_assume x mpz_coerce y order_noswap o ALIAS: GMP::Mpz::overload_subeq = 1 GMP::Mpz::overload_muleq = 2 GMP::Mpz::overload_diveq = 3 GMP::Mpz::overload_remeq = 4 GMP::Mpz::overload_andeq = 5 GMP::Mpz::overload_ioreq = 6 GMP::Mpz::overload_xoreq = 7 PREINIT: static_functable const struct { void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr); } table[] = { { mpz_add }, /* 0 */ { mpz_sub }, /* 1 */ { mpz_mul }, /* 2 */ { mpz_tdiv_q }, /* 3 */ { mpz_tdiv_r }, /* 4 */ { mpz_and }, /* 5 */ { mpz_ior }, /* 6 */ { mpz_xor }, /* 7 */ }; PPCODE: assert_table (ix); (*table[ix].op) (x->m, x->m, y); XPUSHs (ST(0));
First up - I don't really understand this XSub at all. I gather it's also handling -=, *=, /=, %=, &=, |= and ^= via some sort of lookup. The XPUSHs() also puzzles me. What does that achieve ?

Anyway, it seems to me that this particular module has overloaded '+=' and friends without any need to return anything, and without any need to increase the refcount. (I've searched the entire XS file and there's not a single SvREFCNT_inc() to be found.)

Cheers,
Rob
PS: I haven't actually built that GMP module for a while. I assume it works fine with perl-5.8.8, but that's something that's unverified. Last time I built this module, I also benchmarked the overloading and found it to be very efficient - not surprising, given that the author is a smart and talented programmer.

Replies are listed 'Best First'.
Re^3: Overload '+=' with XSub
by Anno (Deacon) on Mar 29, 2007 at 10:51 UTC
    I'm looking at a '+=' overload XSub that neither increments the refcount nor (afaict) returns anything

    Ah, but it does return a value.

    The XPUSHs() also puzzles me. What does that achieve?

    It pushes a value on the return stack. See perlapi.

    Anno

      It pushes a value on the return stack

      Yeaaah ... it pushes a value onto the stack ... but does that mean it returns a value ? (It's also pushing onto the stack something that's already on the stack, isn't it ? .... which doesn't do much to help the intellectually impaired :-) I thought there would have to be an XSRETURN() before anything was returned ... or a RETVAL ....

      We see (in INLINE.h):
      #define Inline_Stack_Push(x) XPUSHs(x)
      Also:
      #define Inline_Stack_Return(x) XSRETURN(x)
      In Inline::C, we have to Inline_Stack_Return(x) if we wish to return anything from a 'void' function. Since Inline::C and XS are essentially one and the same thing, I expected that we would have to explicitly XSRETURN(x) from an XSub (if we wanted to return anything).

      Let's concentrate (for the moment, anyway) on how to rewrite my 'overload_add_eq' in such a way that the refcount increase is not needed. I tried:
      void overload_add_eq(SV * obj, SV * addon, SV * third) { dXSARGS; Card* c = (Card *)SvIV(SvRV(obj)); c->value += SvIV(addon); XPUSHs(obj); }
      but still got the same failure with the '+=" operator. (Again, when explicitly calling overload_add_eq($obj, $addon, 0); there's no problem.)

      Shit!! ... but hang on ... I also tried:
      void overload_add_eq(SV * obj, SV * addon, SV * third) { dXSARGS; Card* c = (Card *)SvIV(SvRV(obj)); c->value += SvIV(addon); XPUSHs(obj); XSRETURN(1); }
      and that worked fine with the '+=' overloading ... and no increase to the refcount !!! It also worked fine when I explicitly called overload_add_eq($obj, $addon, 0);(This might even constitute "progress".)

      So ... I guess one remaining question is "how come I have to call both dXSARGS and XSRETURN (whereas Robert Hyde's GMP code didn't have to do that) ?"

      Another question is "Has anything been achieved by rewriting 'overload_add_eq' ?". I guess the answer to that question will be "no" ... the proof will be in the benchmarking.

      Thanks for the feedback, Anno. Please don't take my questions/objections/refutations as anything other than the ramblings of one who is both ill-informed and a little dim :-)

      Cheers,
      Rob
        To answer thoroughly I'd have to re-read and test more than I find myself inclined, so all I can give you is some hand-waving. You wrote:

        Since Inline::C and XS are essentially one and the same thing ...

        Careful there. They differ quite a bit in some formalities, especially in parameter passing. That's what we're dealing with here.

        So ... I guess one remaining question is "how come I have to call both dXSARGS and XSRETURN (whereas Robert Hyde's GMP code didn't have to do that) ?"

        As far as I remember you normally call neither dXSARGS nor XSRETURN very often yourself. That's true for Inline as well as for bare XS. RETVAL is only for a single scalar return value.

        Speaking of which, why are you doing this the hard way? You have to return exactly one scalar (the modified object), so why not declare the method that way and leave it to Inline?

        Anno

      And if you don't have the time to dig through perlapi, perl tries not to rely on the C stack for manipulation of variables, returning by pushing onto the return stack is the prefered method, assuming you've first set the stack up correctly. While I haven't played with overloading and C I believe the principle is the same.
        returning by pushing onto the return stack is the prefered method

        I proberly nearly almost sort of know something like that :-)

        But I'm still puzzled as to how "pushing onto the return stack" equates to "implicitly returning from the return stack". In my Inline::C experience it (quite frankly) doesn't work that way :-)

        (Btw ... totally inconsequential ... but what's with the "I am Spartacus" stuff ? You forget your password ?)

        Cheers,
        Rob