Closed arunvickram closed 9 months ago
This is because it doesn't work as what happens here is not what you expect to have. First of all, one has to remember that the expression between when
keyword and opening brace of its block is a right side of a smartmatch. Essentially, a when
block is something like
if $_ ~~ <when_expression> { ... when block ... }
except that when
has side effects that we love it for. One of them is the fact that if a when
matches its block can use proceed
and succeed
to manage control flow. But these are only working within a bare block and are not compatible with pointy.
You can see what happens on your own if you add debug prints into the body of &f
. They'll be seen twice in the output.
Also, I wonder wether you noticed the following error from the compiler for the first example:
===SORRY!===
Expression needs parens to avoid gobbling block
Because the right code would be looking like this:
class Point { has Int $.x; has Int $.y }
my $point = Point.new(:1x, :2y);
given $point {
# this `when` isn't able to smart match against a pointy block literal for some reason
when -> Point:D (Int :$x, Int :$y) {
note "THIS IS MATCHER for $x,$y";
}
{ # the when block, actually
note "and this is the actual when block for ", $_;
}
}
And it is essentially the same, as the working example, except that the matcher code is used literally, without assigning it to a variable first.
Interesting. The reason I asked is that I've been trying to get something like this working in one of my programs:
class Point { has Int $.x; has Int $.y }
my $point = Point.new(:1x, :2y);
given $point {
# this `when` isn't able to smart match against a pointy block literal for some reason
matches -> Point (Int :$x, Int :$y) {
say $x + $y;
}
}
I figured that both pointy blocks and subroutines/multimethods are capable of structural pattern matching, but I found it really weird that you couldn't do the same in when
blocks. I had this working:
sub matches(&f) {
$_ = CALLERS::<$_>;
try when &f { f |$_ };
}
but the problem is when I tried applying it here:
class Point { has Int $.x; has Int $.y }
class Circle { has Int $.radius }
my $point = Point.new(:1x, :2y);
given $point {
# this `when` isn't able to smart match against a pointy block literal for some reason
matches -> Point (Int :$x, Int :$y) {
say $x + $y;
}
matches -> Circle (Int :$radius) {
say $radius;
}
default { say "Hello"; }
}
It actually ends up testing all the various statements and runs the default
case as well. I was trying to figure out a way to get that structural pattern matching and destructuring within a given
block with the ability to auto-break like when
, but I kept hitting a brick wall.
@lizmat suggested maybe a slang might be an option here, but I feel like the structural pattern matching in given
that I'm trying to achieve is a logical extension of an already existing feature in Raku: the pattern matching in argument lists in subroutines, and therefore it might be best suited as a standard feature of Raku. Thoughts?
Makes no sense. Local destructuring can be done with my (:$x, :$y) := $point
if necessary. But your case is best covered by multi-dispatching:
proto sub matches(|) {*}
multi sub matches(Point:D (:$x, :$y)) {...}
multi sub matches(Circle:D (:$radius)) {...}
multi sub matches(Shape:D $other-shape) {...} # Shape is a role or a base class
multi sub matches($) { die "Hey, I wanna do some geometry here!" }
# ... somewhere in a galaxy far away ...
$shape = point_or_whatever_it_can_be();
matches($shape);
Let me see how this works in my code and get back to you!
Ah that makes perfect sense, you're basically saying that topicalization makes destructuring unnecessary, right?
You can also use PatternMatching or _::Pattern::Match.
Alright, I'll close this issue because it looks like there are alternatives, but I may revisit this later!
Pretty simple problem. This doesn't work:
The really odd thing is if i assign
-> Point (Int :$x, Int :$y) { ... }
to a variable&f
, this entire thing works:In theory both of these snippets of code I think should be equivalent, but I'm not able to actually do it.