in reply to Overload '+=' with XSub

Normal mutators return the SV after they have changed it. My guess is that overload relies on that.

Anno

Replies are listed 'Best First'.
Re^2: Overload '+=' with XSub
by syphilis (Archbishop) on Mar 29, 2007 at 10:33 UTC
    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.
      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
        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.