develooper Front page | perl.perl5.porters | Postings from October 2015

YA smartmatch proposal [ was: Re: smartmatch needs your eyes]

Thread Previous | Thread Next
From:
Dave Mitchell
Date:
October 7, 2015 08:24
Subject:
YA smartmatch proposal [ was: Re: smartmatch needs your eyes]
Message ID:
20151007082445.GF16789@iabyn.com
On Wed, Oct 07, 2015 at 07:48:34AM +1100, Tony Cook wrote:
>   when { FOO } { ... } # braces not parentheses

Ah sorry, completely failed to spot the new brace syntax!

Anyway, I've been mulling this over, and I've come up with a radical new
proposal for smartmatch. I will now expect this to be shot down in flames
as people point out basic flaws I've overlooked.

What I think we should do:

1. Get rid of the ~~  operator altogether, plus '~~' overloading.

2. Make when's behaviour entirely dependent on the *compile-time* class
of of its arg. In particular, make 'when (FOO)' have exactly the following
behaviours:

    FOO             condition evaluates to
    --------------  ----------------------
    literal undef             !defined($_)
    numeric const                $_ == FOO
    literal pattern              $_ ~= FOO
    all else                     $_ eq FOO

3. when { FOO } has condition FOO.

For example:

    use constant ANS => 42;
    use constant ME  => "davem";

    when (undef)   # equivalent to when { !defined($_) }
    when (42)      # equivalent to when { $_ == 42 }
    when (ANS)     # equivalent to when { $_ == 42 }
    when (42.1)    # equivalent to when { $_ == 42.1 }
    when ("42")    # equivalent to when { $_ eq "42" }
    when ("davem") # equivalent to when { $_ eq "davem" }
    when (ME)      # equivalent to when { $_ eq "davem" }
    when ($x)      # equivalent to when { $_ eq $x }

Rationale:

I think 95% of what people actually *want* a smartmatch system for is so
that they can write code of one of these three forms:

    given ($index) {
        when (undef)     {...}
        when (0)         {...}
        when (1)         {...}
        when (INDEX_MAX) {...}
    }

    given ($string) {
        when (undef) {...}
        when ("foo") {...}
        when ("bar") {...}
        when (BAZ)   {...}
    }

    given ($string) {
        when (undef) {...}
        when (/foo/) {...}
        when (/bar/) {...}
    }

Since perl is about making easy things easy, I think that achieving the
above forms should be our basic goal. If we don't do that, we've failed.
Of course perl likes to make hard things possible too, but I think that is
an auxiliary consideration for now.

Why get rid of the smartmatch operator? I've never really seen the
point of it, apart from being something that exposes the underlying
mechanism of when(), c.f. readline() for <>. If we do keep it, then
it should have exactly the same semantics as I've described above for
when(). Then the condition for when(FOO) would be defined as always
exactly equivalent to  when { $_ ~~ expr }.

Note that my proposal makes when/smartmatch behaviour entirely dependent
on the *compile-time* nature of the RHS. There is no polymorphic dispatch
of any kind. In particular for when($x) it makes no difference if $x is a
qr// or an object or a code ref or is undef: the condition is always
($_ eq $x).

I think the cases where someone has a var $x which could be any of the
above and want perl to dispatch in varied and interesting ways based on
its runtime type are are fairly rare, and can always be coded manually
when really needed, e.g.:

    given (ref $x) {
        when (/CODE/) { $x->($_) }
        when (/REGEX/) { $_ =~ $x }
    }

I think this removes most of the cognitive overhead of the smartmatch
system and makes it genuinely useful.

The only slightly tricky bit is how it decides whether to use == or eq.
The internal compiler rules for given(FOO) would be in its entirety:

    Examine the child of op the when(). If it is:
    OP_UNDEF: compile to !defined($_)
    OP_CONST: if the const's value is IOK or NOK, compile as $_ == CONST
    OP_MATCH: $_ =~ FOO
    else:     compile as $_ eq FOO

From the user's perpective, the rule would be: if its a literal int or
float like 1 or 1.1, use ==. If it's a constant, and the constant's value
was a literal int/float or has been used as an int/float, use' ==', else
use 'eq'.

So these would have their obvious interpretations;

    use constant LIFE => 42;
    use constant FOO => "bar";

while these would be the tricky edge cases where the user might need to read
the docs carefully:

    use constant ERR => $!;

    BEGIN { my $n = "42"; $n += 0 }
    use constant LIFE => $n;

Finally, if the smartmatch operator were freed up, then maybe we could
repurpose it as some sort of recursive grep operator that searches though
nested arrays and hashes for something. That's just a vague thought
though.

Finally finally, regardless of what semantics we finally choose, perhaps
we should use a new feature name for all this, e.g.

    use feature 'switch2';

with 'switch' becoming an error, so that existing code will noisily fail
to compile rather than failing mysteriously on subtle changes to
semantics.


-- 
Little fly, thy summer's play my thoughtless hand
has terminated with extreme prejudice.
        (with apologies to William Blake)

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