So, last year I said "we really ought to cut most of smart match away."
http://www.nntp.perl.org/group/perl.perl5.porters/2011/07/msg174272.html
I've slept on it about 380 times, and I'm still for it. Here's the new plan:
## The New ~~ Operator
$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 $a eq $b
Any Any fatal
This is a nearly a subset of the current behavior. Here are some major points:
(1) This is ordered for the sake of knowing which overload to use first.
(2) A simple scalar (non-reference, non-glob, non-vstring) on the rhs is
used for stringwise equality. I have not yet seen any convincing argument
that we can correctly intuit an eq/== behavior, so we pick one.
Forcing numeric comparison can be done with things like the helpers found in
Smart::Match: things to produce a CodeRef that has the correct behavior.
(3) Container types (array, hash) are no longer treated specially. They were
the most unintuitive case, and they get kicked out. More on that later.
This gets is back to what I've always said is the real power of ~~: a
simple way to provide "a test" to run against a value, where the creator of the
value know just how it will be used. With one exception, we're dispatching
entirely based on the rhs, and they're all obvious.
"Oh no!" you may cry, "What about $x~~@opts? All I wanted was an `in`
operator!"
## Core Junctions
Well, that's why we have junctions. Remember those? Of course you do, they're
fantastic.
if ($x ~~ any( qw( John Paul Ringo ) )) {
tune_strings;
} else {
tap_drumps;
}
We already have very nice junctions in Perl6::Junction. We bring that into the
core (with a new name) and we get nice useful ways to put tests together. We
also get them anywhere else we want them. For me, that's "all over the place."
I bet it will be for lots of other people, too.
## Backcompat and ~~
My anxiety over backward compatibility for ~~ is not gut-wrenching. Still, it
would be nice to do what we can.
After a lot of talk about making ~~ pluggable across different scopes, I think
it's a non-starter. It's just not the kind of thing we can plug this way,
because of the way in which we expect it to be used. If we expect users to
pass a test from their code to some other code, they need to know how that code
will use it. It needs to be the same everywhere.
It would be nice to provide a best-effort backcompat with a deprecation warning
when possible. I'd like to know how good that effort can be. Since the new
table is in many ways a subset of the old one, I think it can be pretty good.
As previously mentioned, the "switch" feature is considered highly
experimental; it is subject to change with little notice. In
particular, both "given" and "when" have tricky behaviours that are
expected to change to become less tricky in the future. Do not rely
upon their current (mis)implementations.
-- perlsyn
## Fixing given and when
I think we already fixed given pretty hard. I need to look at bit more at it,
but let's take it as "fixed enough" for now.
when!
Oh, when, how you trouble me.
I propose that `when(X)` *always* means `$_ ~~ X`. All of the special cases
for parsing and interpreting the inside of when can go. They can all be
reduced to `when(sub{...})`. I would also smile upon `when({...})` acting as a
test block. (Since you can't put a hashref on the rhs of ~~ anymore, there is
no ambiguity.)
The exceptions (from perlsyn's "Experimental Details on given and when") are:
EXCEPTION WAS IS NOW
1. subroutine call -- when (foo())) -- when ({ foo() })
2. regex match -- when ( /foo/ ) -- when (qr/foo/)
-- when ( $_ !~ /foo/) -- when ( none( qr/foo/ ) )
3. smart match -- when ($a ~~ $b) -- when ({ $a ~~ $b })
4. comparison -- when ($a lt $b) -- when ({ $a lt $b })
5. some builtins -- when (eof) -- when ({ eof })
6. negation -- when (! $x) -- when ({ ! $x })
7. bool filetest -- when (-r) -- when ({ -r })
8. flip flops -- when ($a .. $b) -- when ({ $a .. $b })
9. conjunction -- when ($a && $b) -- when ( all( $a, $b ) )
or when ({ $a && $b })
0. disjunction -- when ($a || $b) -- when ( any( $a, $b ) )
or when ({ $a || $b })
Also, `when` should be valid inside an auto-topicalizing `while`, providing an
implicit next, making its behavior more generic so that `when` can be used
safely everywhere that it makes sense.
## In Conclusion
I think this makes ~~ and given/when both totally predictable. I've gone over
this design quite a bit, and I think it turns these features from a liability
to an asset. I also think that we'll be able to eliminate quite a lot of
documentation, which I take as a very good sign. (A lot of that documentation
includes things like "this part is really hard to understand.")
When ~~ works like this, I will use it all the time.
--
rjbs
Thread Next