Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Re^2: Bring back the smartmatch operator (but with sane semantics this time)!

by RonW (Friar)
on Jun 10, 2014 at 23:27 UTC ( #1089464=note: print w/ replies, xml ) Need Help??


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

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.


Comment on Re^2: Bring back the smartmatch operator (but with sane semantics this time)!
Re^3: Bring back the smartmatch operator (but with sane semantics this time)!
by moritz (Cardinal) on Jun 11, 2014 at 14:35 UTC
    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.

      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.

        They do use some B:: trickery, but it's minimal. And the fact is "has it ever been used as xyz before?" is a terrible heuristic. Unfortunately, it's just about the only heuristic available. I love Perl's malleability, but this is one area where it hurts us.

        Internally Perl can store a value that looks to us like a number as an IV/NV (integer/numeric value), or a PV (pointer to a string), or frequently both. This rarely matters to the end user, because numeric operations will autovivify a numeric component, string operations will autovivify a string component, and there's very little ambiguity involved. '==' is always for numeric comparisons. 'eq' is always for string comparisons, and so on. It's generally not necessary for the end user to care about internal representation.

        This all changes for JSON, because JSON does care whether an entity is a number or a string. There's no JSON generic "scalar" as we have in Perl. This is essentially a type mismatch between Perl's "scalars" and JSON's representation of data. People writing and maintaining JSON modules seem to continually struggle with providing a solution that will present the least amount of surprise to end users. At what point should a scalar be mapped to a string for serialization? At what point should it be mapped to a numeric value? It's not an easy question to answer, and that's why you've seen the solution evolve.

        Smartmatch is another example of where the implementation detail necessarily leaks out of the internals to the user. What should "scalar ~~ string" do? What should "scalar ~~ num" do? Should all such matches occur in string context, as though the user had simply used eq? If so, why isn't the user just using eq in the first place? Why should ~~ "smartly" coerce string context to act like eq, but not smartly handle numeric context? (one reason is the JSON problem.)

        The fact that the proposal treats all scalar to scalar comparisons as eq is an example of the whole smartmatch shortcoming. It's supposed to be smart, after all. But as soon as we start trying to make it smart, we end up with a zillion special case rules, and users have to consult a manual every time they try to use it; it's too smart. So we dumb it down to a few simple rules, and then the rules make using it dumb, since we may as well have just used the proper operator in the first place.

        Perl's operators are type specific in a type-free system. The operators are our type system. There is no meta-information inherent in our scalars to tell us they're ints, strings, or floats, because that distinction is totally dynamic, and totally up to the programmer at any given stage in the program's execution. It's the programmer's decision to use '==' or 'eq', for example. If we wanted Perl to try to guess, Perl would have overloaded '+' for concatenation. Languages that go down that road end up with "==" and "===" to provide imprecise hints, and it usually ends in naive misuse and bugs (I would guess that 50% of the PHP code in the wild misuses == and ===).

        Because our operators are how we impose typing on our typeless variables, it becomes highly problematic when we try to invent operators that guess at our meaning in the absence of reliable meta-data. Smartmatch is fine in a language where containers have types. It's madness in a language where operators have types and containers don't.


        Dave

      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
        use 5.014; use strict; use Devel::Peek; my $x = 'not a number'; say 0 + $x; Dump $x; __END__ 0 SV = PVNV(0x1b87050) at 0x1ba83b8 REFCNT = 1 FLAGS = (PADMY,POK,IsCOW,pIOK,pNOK,pPOK) IV = 0 NV = 0 PV = 0x1bafe30 "not a number"\0 CUR = 12 LEN = 14 COW_REFCNT = 1

        By your definition, smart-matching against $x would do a numeric comparision, because it has a numeric slot. There's your WTF right away.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1089464]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (5)
As of 2014-10-01 10:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    What is your favourite meta-syntactic variable name?














    Results (6 votes), past polls