in reply to Re^3: Puzzled by value of $overload::ops{binary}
in thread Puzzled by value of $overload::ops{binary}

In Math::GMPz, the overloading of '++' is:
void overload_inc(pTHX_ SV * p, SV * a, SV * b) { mpz_add_ui(*(INT2PTR(mpz_t *, SvIVX(SvRV(p)))), *(INT2PTR(mpz_t * +, SvIVX(SvRV(p)))), 1); }
which is simply doing p = p + 1, with "p" being a Math::GMPz object.
Then, in the bottom section of the XS file I have:
void overload_inc (p, a, b) SV * p SV * a SV * b CODE: overload_inc(aTHX_ p, a, b); XSRETURN_EMPTY; /* return empty stack */
Works fine.
For the overloading of '+=', it gets a bit drawn out because we might be adding on something other than an IV.
But if we were just dealing with adding on an unsigned long int we would actually have:
SV * overload_add_eq(pTHX_ SV * p, SV * a, SV * b) { mpz_add_ui(*(INT2PTR(mpz_t *, SvIVX(SvRV(p)))), *(INT2PTR(mpz_t * +, SvIVX(SvRV(p)))), SvUV(a)); SvREFCNT_inc(p); return p; }
which is just doing p = p + a, and returning p (after increasing the refcount).
The corresponding code in the bottom section of the XS file would be:
SV * overload_add_eq (p, a, b) SV * p SV * a SV * b CODE: RETVAL = overload_add_eq (aTHX_ p, a, b); OUTPUT: RETVAL
Now, it's not hard to work out what that overload_add_eq() would look like if I were to apply the same approach as used by overload_inc():
void overload_add_eq(pTHX_ SV * p, SV * a, SV * b) { mpz_add_ui(*(INT2PTR(mpz_t *, SvIVX(SvRV(p)))), *(INT2PTR(mpz_t * +, SvIVX(SvRV(p)))), SvUV(a)); }
and
void overload_add_eq (p, second, third) SV * p SV * a SV * b CODE: overload_add_eq(aTHX_ p, a, b); XSRETURN_EMPTY; /* return empty stack */
But I've never managed to get that to work.
It has, however, been a while since I've tried - so I'll have another crack at it tomorrow (as it's now getting late over here) and see if I can get lucky.
(I can't actually remember just what the problem is.)

BTW, I've fiddled about with that code that I've posted, so it might contain one or more typos.

Cheers,
Rob

Replies are listed 'Best First'.
Re^5: Puzzled by value of $overload::ops{binary}
by syphilis (Archbishop) on Jun 26, 2024 at 02:10 UTC
    .... so I'll have another crack at it tomorrow ....

    In GMPz.xs, in the bottom section of the file I have replaced:
    SV * overload_add_eq (a, b, third) SV * a SV * b SV * third CODE: RETVAL = overload_add_eq (aTHX_ a, b, third); OUTPUT: RETVAL
    with
    void overload_add_eq (a, b, third) SV * a SV * b SV * third CODE: overload_add_eq (aTHX_ a, b, third); XSRETURN_EMPTY; /* return empty stack */
    And in the top section of the file I have replaced:
    SV * overload_add_eq(pTHX_ SV * a, SV * b, SV * third) { /* lengthy code snipped */ }
    with
    void overload_add_eq(pTHX_ SV * a, SV * b, SV * third) { PERL_UNUSED_ARG(third); /* UPDATE: This line can be removed as ir +relevant */ mpz_add_ui(*(INT2PTR(mpz_t *, SvIVX(SvRV(a)))), *(INT2PTR(mpz_t * +, SvIVX(SvRV(a)))), SvUV(b)); }
    This means that we're always adding SvUV(b) to a, irrrespective of what b actually is.
    This is good enough for demonstration purposes if we make sure that the second arg (b) is an IV, but we probably don't want to run make test.

    On Windows 11, perl-5.38.0, I then run perl Makefile.PL, followed by make.
    The build emits no warnings.
    Then:
    > perl -Mblib -MMath::GMPz -MDevel::Peek -wle "$x = Math::GMPz->new(12 +34); $x++;print $x; $x += 15; print $x; Dump($x);" 1235 Use of uninitialized value $x in print at -e line 1. SV = PVIV(0x1abd93865e0) at 0x1abdad3ae48 REFCNT = 1 FLAGS = () IV = 1837594613288 PV = 0
    As you can see from that, the Math::GMPz object ($x) has been well and truly clobbered by the '+=' overloading.
    Anyone interested can try this out by making the above alterations to GMPz.xs in https://cpan.metacpan.org/authors/id/S/SI/SISYPHUS/Math-GMPz-0.61.tar.gz.
    Thoughts, observations, opinions and revelations are all most welcome.

    UPDATE: I see the same behaviour on Cygwin, and also on Ubuntu-22.04.4-LTS.

    UPDATE 2: I'll also point out that this altered version of overload_add_eq() works as expected when called as a function:
    > perl -Mblib -MMath::GMPz -MDevel::Peek -wle "$x = Math::GMPz->new(12 +34); $x++; print $x; Math::GMPz::overload_add_eq($x, 15, 0); print $x +;" 1235 1250
    UPDATE 3: Also, if I remove the '+=' overloading (by commenting out the appropriate line in GMPz.pm), then the '+=' overloading (which then uses the '+' overloading) works fine:
    > perl -Mblib -MMath::GMPz -MDevel::Peek -wle "$x = Math::GMPz->new(12 +34); $x++;print $x; $x += 15; print $x; Dump($x);" 1235 1250 SV = IV(0x2bfffa61b78) at 0x2bfffa61b88 REFCNT = 1 FLAGS = (ROK) RV = 0x2bfff38aac8 SV = PVMG(0x2bfffa24a58) at 0x2bfff38aac8 REFCNT = 1 FLAGS = (OBJECT,IOK,READONLY,pIOK) IV = 3023652457216 NV = 0 PV = 0 STASH = 0x2bfffa5e5e8 "Math::GMPz"
    Cheers,
    Rob
      I'd add some debugging checks in overload_add_eq to see what state the SVs are in when they arrive in it. Also, as a matter of good practice, I would keep all the SV-mangling stuff in the XS function, and just pass to your C function the mpz_t (or a pointer) values. If that meant the C functions you've shown here go away, then so be it.
        I keep looking at this piece of overload.pm documentation:
        * *Assignments* += -= *= /= %= **= <<= >>= x= .= &= |= ^= &.= |.= ^.= [snip] The subroutine for the assignment variant of an operator is required only to return the result of the operation.
        That seems to me to be asserting that these operations (unlike '++' and '--') do require a value to be returned.
        And it also looks to me that overload.pm is somehow enforcing that policy.

        This following rewrite of the simplified overload_add_eq C and XS functions works fine:
        void overload_add_eq(pTHX_ SV * a, SV * b, SV * third) { dXSARGS; PERL_UNUSED_ARG(third); mpz_add_ui(*(INT2PTR(mpz_t *, SvIVX(SvRV(a)))), *(INT2PTR(mpz_t * +, SvIVX(SvRV(a)))), SvUV(b)); XSRETURN(1); }
        and
        void overload_add_eq (a, b, third) SV * a SV * b SV * third CODE: overload_add_eq (aTHX_ a, b, third); XSRETURN(1);
        But I wonder if that achieves anything significant over the implementation that has been working fine for the last umpteen years.

        Anyway, I don't want to get too bogged down in this - though it's certainly interesting enough to encourage a bit more investigation.

        Cheers,
        Rob