Mailing List Archive

Missing sv_numeq() function?
The behaviour in perl's `eq` operator is exposed to XS authors via

BOOL sv_eq(SV *left, SV *right);

Nice and simple.

As far as I can tell there isn't an equivalent numerical one, for `==`.
I've had to write myself a 47 line wrapper function by copying out the
logic from Perl's (non-API-exposed) Perl_do_ncmp() function.

I propose adding an API function

BOOL sv_numeq(SV *left, SV *right);

to cover this.

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Missing sv_numeq() function? [ In reply to ]
On Fri, 20 Aug 2021 11:55:00 +0100
"Paul \"LeoNerd\" Evans" <leonerd@leonerd.org.uk> wrote:

> As far as I can tell there isn't an equivalent numerical one, for
> `==`. I've had to write myself a 47 line wrapper function by copying
> out the logic from Perl's (non-API-exposed) Perl_do_ncmp() function.

For further context:

https://metacpan.org/release/PEVANS/Syntax-Keyword-Match-0.07/source/lib/Syntax/Keyword/Match.xs#L35-85

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Missing sv_numeq() function? [ In reply to ]
On Fri, Aug 20, 2021 at 11:55:00AM +0100, Paul "LeoNerd" Evans wrote:
> The behaviour in perl's `eq` operator is exposed to XS authors via
>
> BOOL sv_eq(SV *left, SV *right);
>
> Nice and simple.

That's not quite accurate. Overloaded comparison is handled one level out:

PP(pp_seq)
{
dSP;
tryAMAGICbin_MG(seq_amg, 0);
{
dPOPTOPssrl;
SETs(boolSV(sv_eq_flags(left, right, 0)));
RETURN;
}
}


> As far as I can tell there isn't an equivalent numerical one, for `==`.
> I've had to write myself a 47 line wrapper function by copying out the
> logic from Perl's (non-API-exposed) Perl_do_ncmp() function.
>
> I propose adding an API function
>
> BOOL sv_numeq(SV *left, SV *right);
>
> to cover this.


That's probably sane, but:


On Fri, Aug 20, 2021 at 01:26:37PM +0100, Paul "LeoNerd" Evans wrote:
> On Fri, 20 Aug 2021 11:55:00 +0100
> "Paul \"LeoNerd\" Evans" <leonerd@leonerd.org.uk> wrote:
>
> > As far as I can tell there isn't an equivalent numerical one, for
> > `==`. I've had to write myself a 47 line wrapper function by copying
> > out the logic from Perl's (non-API-exposed) Perl_do_ncmp() function.
>
> For further context:
>
> https://metacpan.org/release/PEVANS/Syntax-Keyword-Match-0.07/source/lib/Syntax/Keyword/Match.xs#L35-85

The documentation of sv_eq is:

=for apidoc sv_eq

Returns a boolean indicating whether the strings in the two SVs are
identical. Is UTF-8 and S<C<'use bytes'>> aware, handles get magic, and will
coerce its args to strings if necessary.


The code in do_ncmp() doesn't handle overloading, and also is dealing in
SvIVX() etc rather than SvIV(). So I don't think that it's totally the
right implementation to expose, on the assumption that

1) What sv_eq_flags() is a better API
2) And if it isn't, it would be better if we exposed consistent API

Nicholas Clark
Re: Missing sv_numeq() function? [ In reply to ]
On Fri, 20 Aug 2021 13:09:00 +0000
Nicholas Clark <nick@ccl4.org> wrote:

> On Fri, Aug 20, 2021 at 11:55:00AM +0100, Paul "LeoNerd" Evans wrote:
> > The behaviour in perl's `eq` operator is exposed to XS authors via
> >
> > BOOL sv_eq(SV *left, SV *right);
> >
> > Nice and simple.
>
> That's not quite accurate. Overloaded comparison is handled one level
> out:
>
> PP(pp_seq)
> {
> dSP;
> tryAMAGICbin_MG(seq_amg, 0);
> {
> dPOPTOPssrl;
> SETs(boolSV(sv_eq_flags(left, right, 0)));
> RETURN;
> }
> }

Ah, yes I was aware of that but I didn't explain that in the email.

> That's probably sane, but:
> 1) What sv_eq_flags() is a better API
> 2) And if it isn't, it would be better if we exposed consistent API

Yes good ideas there - an sv_numeq_flags() would be better.

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Missing sv_numeq() function? [ In reply to ]
On Fri, 20 Aug 2021 11:55:00 +0100
"Paul \"LeoNerd\" Evans" <leonerd@leonerd.org.uk> wrote:

> I propose adding an API function
>
> BOOL sv_numeq(SV *left, SV *right);
>
> to cover this.
>

Update: here's an initial attempt, including docs and XS::APItests:

https://github.com/leonerd/perl5/tree/sv_numeq


Thinking further about this, I think I'd like to define a new SV_* flag
to request that the function also perform operator overloading. This
new sv_numeq() would recognise that flag, and I'd also add support to
the existing sv_eq(). (Which, is stringy. In hindsight it should have
been named sv_streq(), but too late now (unless we rename it maybe?))


Perhaps it would be named something like `SV_TRYAMAGIC`. Or maybe the
less cryptic `SV_OVERLOAD` (though we already have an unrelated flag,
`SV_SKIP_OVERLOAD` which the various sv_2Xv_flags() functions all take).

`SV_OVERLOAD` would be nice, except it's a bit messy having some
_flags()-like functions that do overloading by default and have a flag
to tell them not to, vs. other flagsy functions that don't but take a
flag to tell them to.


Unless.....

Maybe I can solve all of these issues in one go, by making a new
sv_streq_flags() which does overload by default, and put that behaviour
in my new sv_numeq_flags() as well, then these functions can all respond
to the same SV_SKIP_OVERLOAD flag in the same way. Then sv_eq() and
sv_eq_flags() become wrappers of sv_streq_flags() which do pass the
SV_SKIP_OVERLOAD flag. I think it would be nice to do overload by
default as that's generally "the nice thing to do", and a flag to turn
it off for specific circumstances.


Thoughts?

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Missing sv_numeq() function? [ In reply to ]
I've given it a run and it looks pretty good here.

I came across one interesting little anomaly:
############################
use strict;
use warnings;
use Math::BigRat;
use Test::More;

use Inline C => <<'EOC';

int is_eq(SV * n1, SV * n2) {
if(sv_numeq(n1, n2)) return 1;
return 0;
}

EOC

my $bigq1 = Math::BigRat->new(
'3602879701896397/36028797018963968'
);
my $bigq2 = Math::BigRat->new(
'1/10'
);

cmp_ok($bigq1, '!=', $bigq2, "Rationals are unequal");
cmp_ok(is_eq($bigq1, $bigq2), '!=', 1, "sv_numeq detects inequality");

done_testing
#############################

This outputs:

ok 1 - Rationals are unequal
not ok 2 - sv_numeq detects inequality
# Failed test 'sv_numeq detects inequality'
# at sv_numeq.pl line 23.
# got: 1
# expected: anything else

Both of those rationals equate to the double 0.1. (The first is an exact
rational representation of the value contained in that double; the second
rational rounds to that same double.)
I don't know if anything could be done about that.
On investigation, it seems that sv_numeq() is performing the division
that's implicit in the rationals, resulting in 2 doubles that contain the
same value (0.1). Unsurprisingly it therefore returns true.

2 additional tests (based on my initial, somewhat hopeful, expectations)
that I ran were:

cmp_ok(is_eq(0.1, $bigq1), '==', 1, "sv_numeq agrees that 0.1 == \$bigq1");
cmp_ok(is_eq(0.1, $bigq2), '!=', 1, "sv_numeq agrees that 0.1 != \$bigq2");

which resulted in:

ok 3 - sv_numeq agrees that 0.1 == $bigq1
not ok 4 - sv_numeq agrees that 0.1 != $bigq2
# Failed test 'sv_numeq agrees that 0.1 != $bigq2'
# at sv_numeq.pl line 25.
# got: 1
# expected: anything else

Oh ... and I think there's a simple typo in the docs:
<quote>
"sv_numeq"
A convenient shortcut for calling "sv_numeq" with the "SV_GMAGIC"
flag.
</quote>
I suspect the second occurrence of "sv_numeq" should be "sv_numeq_flags" ?

Cheers,
Rob


On Mon, Sep 13, 2021 at 1:59 AM Paul "LeoNerd" Evans <leonerd@leonerd.org.uk>
wrote:

> On Fri, 20 Aug 2021 11:55:00 +0100
> "Paul \"LeoNerd\" Evans" <leonerd@leonerd.org.uk> wrote:
>
> > I propose adding an API function
> >
> > BOOL sv_numeq(SV *left, SV *right);
> >
> > to cover this.
> >
>
> Update: here's an initial attempt, including docs and XS::APItests:
>
> https://github.com/leonerd/perl5/tree/sv_numeq
>
>
> Thinking further about this, I think I'd like to define a new SV_* flag
> to request that the function also perform operator overloading. This
> new sv_numeq() would recognise that flag, and I'd also add support to
> the existing sv_eq(). (Which, is stringy. In hindsight it should have
> been named sv_streq(), but too late now (unless we rename it maybe?))
>
>
> Perhaps it would be named something like `SV_TRYAMAGIC`. Or maybe the
> less cryptic `SV_OVERLOAD` (though we already have an unrelated flag,
> `SV_SKIP_OVERLOAD` which the various sv_2Xv_flags() functions all take).
>
> `SV_OVERLOAD` would be nice, except it's a bit messy having some
> _flags()-like functions that do overloading by default and have a flag
> to tell them not to, vs. other flagsy functions that don't but take a
> flag to tell them to.
>
>
> Unless.....
>
> Maybe I can solve all of these issues in one go, by making a new
> sv_streq_flags() which does overload by default, and put that behaviour
> in my new sv_numeq_flags() as well, then these functions can all respond
> to the same SV_SKIP_OVERLOAD flag in the same way. Then sv_eq() and
> sv_eq_flags() become wrappers of sv_streq_flags() which do pass the
> SV_SKIP_OVERLOAD flag. I think it would be nice to do overload by
> default as that's generally "the nice thing to do", and a flag to turn
> it off for specific circumstances.
>
>
> Thoughts?
>
> --
> Paul "LeoNerd" Evans
>
> leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
> http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
>
Re: Missing sv_numeq() function? [ In reply to ]
sisyphus <sisyphus359@gmail.com> wrote:
:On investigation, it seems that sv_numeq() is performing the division
:that's implicit in the rationals, resulting in 2 doubles that contain the
:same value (0.1). Unsurprisingly it therefore returns true.

Right, it is not honouring overloaded '==', instead taking the overloaded
numify of both sides.

A quick look suggests to me that sv_eq_flags is similarly not looking for
overloaded 'eq'.

Hugo
Re: Missing sv_numeq() function? [ In reply to ]
On Wed, 15 Sep 2021 00:02:10 +1000
sisyphus <sisyphus359@gmail.com> wrote:

> Oh ... and I think there's a simple typo in the docs:
> <quote>
> "sv_numeq"
> A convenient shortcut for calling "sv_numeq" with the
> "SV_GMAGIC" flag.
> </quote>
> I suspect the second occurrence of "sv_numeq" should be
> "sv_numeq_flags" ?

Oops, yes indeed.

Fixed [sv_numeq 45a7382b04] Small docs fix (thanks sisyphus)

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Missing sv_numeq() function? [ In reply to ]
On Tue, 14 Sep 2021 15:04:35 +0100
hv@crypt.org wrote:

> Right, it is not honouring overloaded '==', instead taking the
> overloaded numify of both sides.
>
> A quick look suggests to me that sv_eq_flags is similarly not looking
> for overloaded 'eq'.

Indeed they do not obey overload currently. Hence my entire followup
reply.

Perhaps they should by default, and take a flag to ask them not to?

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Missing sv_numeq() function? [ In reply to ]
"Paul \"LeoNerd\" Evans" <leonerd@leonerd.org.uk> wrote:
:On Tue, 14 Sep 2021 15:04:35 +0100
:hv@crypt.org wrote:
:
:> Right, it is not honouring overloaded '==', instead taking the
:> overloaded numify of both sides.
:>
:> A quick look suggests to me that sv_eq_flags is similarly not looking
:> for overloaded 'eq'.
:
:Indeed they do not obey overload currently. Hence my entire followup
:reply.
:
:Perhaps they should by default, and take a flag to ask them not to?

Yes, sorry if I was unclear: I was trying to clarify for sisyphus the
behaviour he was seeing.

It does occur to me though that since it _is_ honouring the numify
overload, the story is somewhat muddied.

Hugo
Re: Missing sv_numeq() function? [ In reply to ]
On Sun, 12 Sep 2021 16:59:08 +0100
"Paul \"LeoNerd\" Evans" <leonerd@leonerd.org.uk> wrote:

> Maybe I can solve all of these issues in one go, by making a new
> sv_streq_flags() which does overload by default, and put that
> behaviour in my new sv_numeq_flags() as well, then these functions
> can all respond to the same SV_SKIP_OVERLOAD flag in the same way.
> Then sv_eq() and sv_eq_flags() become wrappers of sv_streq_flags()
> which do pass the SV_SKIP_OVERLOAD flag. I think it would be nice to
> do overload by default as that's generally "the nice thing to do",
> and a flag to turn it off for specific circumstances.

Further update: I've decided that it probably makes sense for it to do
overloading, unless told not to with the SV_SKIP_OVERLOAD flag. So now
it does:

[sv_numeq e47b37a026] Have sv_numeq() respect == overloading unless the SV_SKIP_OVERLOAD flag is passed

After this PR is merged, I think I'll do the same for adding an
sv_streq() with the same API shape; thus fixing the odd name of sv_eq()
and its lack of overloading support at the same time.

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Missing sv_numeq() function? [ In reply to ]
On Wed, Sep 15, 2021 at 6:32 AM Paul "LeoNerd" Evans <leonerd@leonerd.org.uk>
wrote:

> [snip}
>
> [sv_numeq e47b37a026] Have sv_numeq() respect == overloading unless the
> SV_SKIP_OVERLOAD flag is passed
>

Sorry for the delay in responding - I initially completely mis-read Paul's
last post as meaning that there would be nothing more for me to test until
the PR was merged.
That's now looking *really* good, IMO ;-))

There's still a problem wrt Math::BigRat, but it's a problem with that
module's overloading of '==' (see See
https://github.com/Perl/perl5/issues/19139), not a problem with the
sv_numeq implementation.

Thank you Hugo, for the comments you provided. (They helped.)
Nice work, Paul !! Let's get it merged,and see if anything ensues from that.

Cheers,
Rob
Re: Missing sv_numeq() function? [ In reply to ]
On Fri, 20 Aug 2021 11:55:00 +0100
"Paul \"LeoNerd\" Evans" <leonerd@leonerd.org.uk> wrote:

> The behaviour in perl's `eq` operator is exposed to XS authors via
>
> BOOL sv_eq(SV *left, SV *right);
>
> Nice and simple.
>
> As far as I can tell there isn't an equivalent numerical one, for
> `==`. I've had to write myself a 47 line wrapper function by copying
> out the logic from Perl's (non-API-exposed) Perl_do_ncmp() function.
>
> I propose adding an API function
>
> BOOL sv_numeq(SV *left, SV *right);

I realised I didn't get around to raising this as a PR. Oops.

Here now:

https://github.com/Perl/perl5/pull/19368

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/