develooper Front page | perl.perl5.porters | Postings from August 2012

Re: fixing smartmatch just hard enough (and when, too)

Thread Previous | Thread Next
From:
Damian Conway
Date:
August 19, 2012 14:43
Subject:
Re: fixing smartmatch just hard enough (and when, too)
Message ID:
CAATtAp7vxoPtUdUkj_4mAgQMkfM6m-1tnQJvC1gNYxaxJ6_YZw@mail.gmail.com
I must say I was very uncertain when Rick first talked with me about
this proposed second attempt to fix smartmatching. But having talked
with him at length about the issue during OSCON, I am now in strong
agreement that this proposal represents a genuine 'fix', rather than
just yet another unnecessary change.

The current smartmatching table, with its 23 cases, is simply far too
complex for real humans to handle. And the fact that there are a further
8 exceptions for smartmatching inside a 'when' (and not just exceptions
to the table, but exceptions to standard Perl semantics as well) makes
the entire feature more-or-less unusable for most people.

The new proposal has only six smartmatching cases and only one special
syntax for 'when' (of which, more below). I think that might make
smartmatching sufficiently predictable and usable for the vast majority of Perl
developers to consider it a viable tool.

And the addition of:

    use junctions;

(or whatever) to the core would have enormous benefits beyond just
smartmatching.

My main concern was always the removal of all the hash- and array-based
cases, but in thinking about that I eventually realized that I couldn't
actually remember them all myself. And that I wasn't even sure about
most of ones that I could remember, except for @ARRAY~~@ARRAY
and $ANY~~@ARRAY.

For example, I know there's a table entry for %HASH~~@ARRAY,
but I'm not sure whether the meaning of that is:

    any(  keys %HASH) ~~ any(@ARRAY)
    any(values %HASH) ~~ any(@ARRAY)
    all(  keys %HASH) ~~ any(@ARRAY)
    all(values %HASH) ~~ any(@ARRAY)
    any(  keys %HASH) ~~ all(@ARRAY)
    any(values %HASH) ~~ all(@ARRAY)

Moreover, I'm not even sure whether @ARRAY~~%HASH
does the same thing as %HASH~~@ARRAY.

The point being, that all of the above junction-based versions are
perfectly clear to me, and were easy to get right in the first place.
And the current smartmatching table doesn't even offer 5/6 of them.

My point is that if even the original proponent of smartmatching can't
use it without RTFM-ing, how can we consider the current arrangement
anything but broken? And how can reducing the current table+special cases
from 31 to 7 be anything but a vast improvement?

My one point of disagreement with Rick's current proposal is that,
like Abigail, I feel it's essential for smartmatching (and hence 'when')
to handle matching numbers sensibly. And by sensibly, I mean "not with eq".

A simple failure-case I have already mentioned privately to Rick is this:

   while (readline) {
        when (undef)    { say 'done'; last;  }
        when (0)        { say 'must be +ve'; }
        when (any 1..9) { say 'digit';       }
        default         { die 'horribly';    }
    }

...which dies horribly even when a single digit is correctly typed in.

The behaviour I proposed instead was that the full table should be:

    $a      $b                  Meaning
    ======= =======             ======================
    Any     undef               ! defined $a
    Any     ~~-overloaded       ~~ overloading is used
    ~~-ol   Any                 ~~ overloading is used (reversed)
    Any     CodeRef, &{}-ol     $b->($a)
    Any     Regexp, qr-ol       $a =~ $b
    Any     Simple              looks_like_num($a) && looks_like_num($b)
                                    ? $a == $b
                                    : $a eq $b
    Any     Any                 fatal

That is, exactly the same table as Rick proposes, except that a smartmatch
between two simple scalars that could reasonably be considered numbers
will actually use numeric matching.

As regards the 'when' reboot, anything we can do to get rid of those eight
special cases--which don't behave like anything else in Perl 5--would be
a blessing.

And for that very reason (avoiding one-off special syntax and semantics),
I also think that the new block syntax for 'when' should be:

    when  {CODE}  {...}

not:

    when ({ CODE }) {...}

because everywhere else that Perl uses a raw block as a thunk
(e.g. 'map', 'grep', 'sort'), the opening curly can come immediately
after the keyword, no parens required. And, given that anonymous
hashes would no longer be allowed as arguments to 'when', there's no
possible ambiguity without the parens.

In contrast, a set of curlys is *never* a block when it's the only thing in a
set of parens...it's always a hash constructor). It would be far better to keep
it that way, than to add a new syntactic special case just for 'when'.

Anyway (FWIW, and with that one caveat about numeric matching)
I just wanted to say that I'm fully in favour of this proposed fix,
despite the hassle of breaking backwards compatibility (again).

Damian

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About