Larry Wall wrote:
Anyway, that gives us:

    given $pattern {
        when .accepts(42) {...}
    }

which given typical usage patterns of switch statements is probably
adequately huffmanized, unless we want to go for something shorter
than accepts/rejects, like

    acc/rej
    pix/nix
    ok/bogus

...at which point, legibility becomes an issue.  .accepts() and
.rejects() seem to work well enough on a case-by-case basis - although
it occurs to me that someone who intends to put the pattern first
within a given/when construct is probably going to want to do so for
every case, or very nearly so:

 given $pattern {
   when .accepts($a) { ... }
   when .accepts($b) { ... }
   when .accepts($c) { ... }
   when .accepts($d) { ... }
 }

It would be nice if there were some way to "factor out" the .accepts()
in the above code.  Maybe something like:

 given $pattern {
   when $a { ... } # if $a ~~ $pattern { ... ; next }
   when $b { ... } # if $b ~~ $pattern { ... ; next }
   when $c { ... } # if $c ~~ $pattern { ... ; next }
   when $d { ... } # if $d ~~ $pattern { ... ; next }
 } is backward;

Although I don't like the fact that you have to wait until reading the
whole block to find out that the cases are being processed inside-out.

--

Would it be possible to put a closure on the left and an argument list
on the right, with the effect being that the closure gets called using
the argument list?  This would let you do something like:

 given { ^x ~~ $pattern } {
   when $a { ... } # if $a ~~ $pattern { ... ; next }
   when $b { ... } # if $b ~~ $pattern { ... ; next }
   when $c { ... } # if $c ~~ $pattern { ... ; next }
   when $d { ... } # if $d ~~ $pattern { ... ; next }
 }

or

 given { ^x <= $number < ^y } {
   when 1, 2 { ... } $ if 1 <= $number < 2 { ... ; next }
   when 2, 3 { ... } $ if 2 <= $number < 3 { ... ; next }
 }

(Yes, I know that this second case could be handled more flexibly
using right-side Ranges.  TIMTOWTDI.)

The main problem that I have with this idea is its rigidity.  The
_only_ way that the topic can be used in the above is as a test for
the 'when' clauses; and it messes with the 'when *' idiom.  (But then,
any code that follows the final 'when' in a block is already the 'if
all else fails...' code; 'when *' is merely syntactic sugar to
highlight this fact.)

--

It would be nice to have something that is to 'given' as 'loop' is to
'for', letting you specify a topic and a separate case tester up
front:

 test $pattern, { $^x ~~ $_ } {
   when $a { ... } # if $a ~~ $pattern { ... ; next }
   when $b { ... } # if $b ~~ $pattern { ... ; next }
   when $c { ... } # if $c ~~ $pattern { ... ; next }
   when $d { ... } # if $d ~~ $pattern { ... ; next }
 }

Or, to avoid additional keywords, just say that a 'given' statement
with two arguments uses the first argument as its topic and the second
argument as the case tester to replace '{ $_ ~~ $^x }' in 'when'
clauses.  Better, use 'when' as is, but introduce a 'test' alternative
that is customized by the second parameter:

 given $pattern, { $^x ~~ $_ } {
   test $a { ... } # if $a ~~ $pattern { ... ; next }
   test $b { ... } # if $b ~~ $pattern { ... ; next }
   test $c { ... } # if $c ~~ $pattern { ... ; next }
   test $d { ... } # if $d ~~ $pattern { ... ; next }
   when * { ... } # if $pattern ~~ * { ... ; next }
 }

That way, 'given' and 'when' still behave exactly as currently
described; the case tester only comes into play when you explicitly
ask for it.

--

At this point, though, the case tester is looking like it might be
better as a property of the 'given' block:

 given $pattern {
   TEST { $^x ~~ $_ }
   test $a { ... } # if $a ~~ $pattern { ... ; next }
   test $b { ... } # if $b ~~ $pattern { ... ; next }
   test $c { ... } # if $c ~~ $pattern { ... ; next }
   test $d { ... } # if $d ~~ $pattern { ... ; next }
   when * { ... } # if $pattern ~~ * { ... ; next }
 }

Or go ahead and let TEST change the behavior of 'when' within the
block, and rely on nested blocks to allow different kinds of tests
within a 'given' block:

 given $pattern
 {
   {
     TEST -> $x { $x ~~ $_ }
     when $a { ... } # if $a ~~ $pattern { ... ; next }
     when $b { ... } # if $b ~~ $pattern { ... ; next }
     when $c { ... } # if $c ~~ $pattern { ... ; next }
     when $d { ... } # if $d ~~ $pattern { ... ; next }
   }
   when * { ... } # if $pattern ~~ * { ... ; next }
 }

...and someone silly enough to want to frequently change the case
tester within a given block is advised to use 'if' instead.

What do you think?

--
Jonathan "Dataweaver" Lang

Reply via email to