http://qs321.pair.com?node_id=1089450


in reply to Bring back the smartmatch operator (but with sane semantics this time)!

At first glance, I like your proposal.

One thing that will surprise people is that it contains no provision for numeric comparison, so by the numeric/string duality, numbers will be compared as strings.

I have my doubts about the cases you're not sure about; distinguishing barewords from strings is impossible in non-strict mode (which I rarely use, but which is still a big part of perl, whether you like it or not).

Ranges become flipflops in scalar context and a list in list context, so doing a range comparison seems pretty much inconsistent with the rest of the language.

Comparing lists with any-semantics requires the right-hand side of the ~~ to be evaluated in list context, which IMHO would be a bit surprising.

  • Comment on Re: Bring back the smartmatch operator (but with sane semantics this time)!

Replies are listed 'Best First'.
Re^2: Bring back the smartmatch operator (but with sane semantics this time)!
by smls (Friar) on Jun 10, 2014 at 22:17 UTC
    One thing that will surprise people is that it contains no provision for numeric comparison, so by the numeric/string duality, numbers will be compared as strings.

    Yes, I agree that this is the biggest weakness of the suggested rules.

    The problem of surprise could be partially mitigated by emitting a warning when a numeric literal is used as the RHS of a smartmatch (or as a when-expression), but of course numbers coming in through variables would still silently use string comparison.

    As for there being no way to employ numeric comparison, in theory people could create a Num class that overloads ~~ and forces numeric comparison, but such a solution likely won't be worth it to users of smartmatch or given/when (since the whole point of those features is to make things simpler).
    So I guess the case of numeric comparisons simply won't be covered, or rather, people will be forced to write it out verbosely:

    given ($_ == 5) { ... } $foo ~~ sub { shift == 5 }

    Not ideal, but also not necessarily a deal-breaker.

    Of course, I would love to be proved wrong regarding separate string/number dispatch not being possible to do safely in Perl... :)

    I have my doubts about the cases you're not sure about; distinguishing barewords from strings is impossible in non-strict mode (which I rarely use, but which is still a big part of perl, whether you like it or not).

    Ranges become flipflops in scalar context and a list in list context, so doing a range comparison seems pretty much inconsistent with the rest of the language.

    Comparing lists with any-semantics requires the right-hand side of the ~~ to be evaluated in list context, which IMHO would be a bit surprising.

    All good points. I guess it's better to leave those rules out then.

    As for junction semantics, it occurred to me that the problems/warts of the existing Junction module(s) on CPAN would probably go away once ~~ like described above (but without the three "bonus" rules) is in core and those classes have been updated to overload it (rather than relying on hacks like overloading == for non-standard things.

    So, support for  $topic ~~ any('foo', 'bar', qr/baz/)  would then be provided by those modules and would not need to be hacked into the smartmatch operator itself.

    And if, at a later time, one of those junction modules makes it into core too, then all the better.

Re^2: Bring back the smartmatch operator (but with sane semantics this time)!
by RonW (Parson) on Jun 10, 2014 at 23:27 UTC
    One thing that will surprise people is that it contains no provision for numeric comparison, so by the numeric/string duality, numbers will be compared as strings.

    Internally, Perl knows when to implicitly convert a number to a string and vice-verse, so a new smart match should be able to know when it's dealing with numbers.

    Following the proposed "RHS decides the op", then when the RHS is an actual number, it could coerce the LHS to a number.1

    Overall, I like this proposal. It is far better than loosing smart match (and, especially, given/when).

    ---

    1In theory it could check both sides for numbers, but I would rather let the RHS blindly impose numericy on the LHS for consistency.

      Following the proposed "RHS decides the op", then when the RHS is an actual number, it could coerce the LHS to a number.

      It's the when the RHS is an actual number that's problematic. When do you consider something a number? The fact that I have happened to know that both Mojo::JSON and JSON::Tiny recently adjusted their heuristic for what to consider a number (and at least Mojo::JSON has been around for quite some time before) doesn't make me very optimistic that there is a reasonable way to answer that question in perl 5, precisely because of the automagic coercion / SV-NV duality.

        When do you consider something a number?

        I personally would just go for a technical, non-heuristic approach:

        • Numbers: 42, $scalar+0, $scalar having a defined numeric context slot
        • Non-numbers: 'quoted string', $scalar

        If Perl, itself, does not internally know a value is a number, how can it convert a number to a string?

        Looking at Mojo::JSON and JSON::Tiny, they both seem to be "pure Perl" implementations, so they would have to use heuristics.

        Looking at perlapi:

        SvNIOK "Returns a U32 value indicating whether the SV contains a number, integer or double."

        So, it seems that, internally, Perl knows if a scalar is a number.

Re^2: Bring back the smartmatch operator (but with sane semantics this time)!
by RonW (Parson) on Jun 11, 2014 at 23:52 UTC

    If we had to live with only having string compare on scalar values, it could be worked around by nesting given with in the default clause of another given:

    given (+ $x) { when (+ $n) { ... } when (+ $m) { ... } default { given ($x) { ... } }

    But, having dug in to Perl Guts more than I should have, I think that disallowing tied (and probably other magic) variables on the RHS, a built-in smart match would be able to reliably determine if the RHS is a number.

      But, having dug in to Perl Guts more than I should have, I think that disallowing tied (and probably other magic) variables on the RHS, a built-in smart match would be able to reliably determine if the RHS is a number.

      The problem is that Perl doesn't expose the concept "this scalar is a number" to the user (by design). Thus making a decision based on whether a scalar is a number is nearly always wrong.

      A piece of code that already makes such a decision is the code that decides whether to warn on a numeric operation:

      $ perl -wE 'say 0 + "1.2"' 1.2 $ perl -wE 'say 0 + "1.2.3"' Argument "1.2.3" isn't numeric in addition (+) at -e line 1. 1.2

      So, what do I keep complaining about? A real problem are dual vars. Those aren't just a rare corner case that should be avoided, but for example the result from boolean operators:

      $ perl -wE 'say 0 + !1' # no warning 0 $ perl -wE 'my $false = !1; say "<<$false>>"' # empty string! <<>>

      So it's a number, but it's also an empty string. Should smart-matching against that be numeric or string comparison? My intuitive reaction is "string comparison", because $false doesn't round-trip when converted to a number and then to a string.

      But you can also construct valid cases where round-tripping to a number is the wrong criterion; an example is if a user-supplied string is never used as a number, but happens to look like a number. You certainly don't want those values to try to coerce your own strings to numbers (and warn).

      So, however you decide whether a scalar is number or a string for the purpose of comparision, I can point out a case where your decision is a big WTF. Which is precisely the reason that we have separate == and eq operators.

      Whatever will be done about that, the string/number duality will remain a weakness of any Perl 5 smartmatch proposal.