Use of implicit parameter in for-loop causes hang
Your code using $_
contains the moral equivalent of:
/''+/
which loops forever (because the empty string ''
matches an infinite number of times).
(Well, I've shown just a simple match, and $_
must be assigned or bound to some value that coerces to a string or the infinite loop won't happen, and your code has to go around its loop twice for it to become a moral equivalent to the above, but those are red herrings.)
is there some finer detail while using the implicit
$_
that I don't understand?
From the smartmatch doc:
The smartmatch operator aliases the left-hand side to
$_
In code:
lhs ~~ rhs;
is equivalent to:
$_ := lhs;
rhs.ACCEPTS(lhs);
I suspect you're not taking the first of the two lines above into account.
(Just use the second line on its own if you wish to avoid this topicalization.1)
Presuming $_
is assigned a defined non-empty string:
s/$_//;
will always update $_
to be an empty string (''
).
And:
$a ~~ s/^ ($_+) //;
will alias $_
to $a
and then update both $_
and $a
to be an empty string.
So the second time around the for
loop the ~~
again aliases $_
to $a
, which now contains an empty string, and then you arrive at the infinite loop condition my answer began with.
Footnotes
1 In a comment below Jo asks why ~~
needs to "topicalize" (alias $_
to the lhs). The authoritative answer is presumably stored in @Larry's collective brain, which is arguably expressed best by the P6 design documents (in page searches for "smart match" and "smartmatch" seem to be the ticket). But I'll write my own thoughts on this matter.
First, aiui, it doesn't need to be this way.
Aiui @Larry could have just decided that constructs that rely on the current topic (which I think means //
, s///
and suitable routine calls) do as they do with P5.
Here's some code that runs in both P5 (with suitable pragmas) and P6:
my $a = 'a value';
$_ = 'another value';
say $a ~~ s/value/changed string/;
say $a;
say $_;
What would you expect the results to be?
In P5:
a value
another changed string
In P6:
「value」
a changed string
another value
P5 leaves $a
untouched, modifies $_
, then compares the modified result with the original $a
and concludes they don't match (so the say $a ~~ ...
line says a blank line).
P6 aliases the $_
to $a
for the duration of the smart match, leaves $a
permanently modified per the s///
, and restores $_
to its prior value afterwards.
If we stuck with the P5 way we also couldn't write stuff like:
foo ~~ / ... /
and have it be true iffoo
matches the regex;my $a = 'AA'; $a ~~ .uc
and have it be true regardless of the value of$_
before or after this bit of code;foo ~~ .&bar
match wherebar
is a sub expecting an argument and we want it to getfoo
.
In the meantime, .ACCEPTS
is also available. So it's not like you can't do the same thing as P5. It's just that, by default, constructs that act on the topic work as perhaps folk might expect if they weren't exposed to P5 first, and @Larry
deemed that a good thing overall.
In summary, Jo, I hear that P5 does what you expect, but presume that's at least in part because you've used P5 and your expectations are based in large part on what it does, and wonder if it remains what you prefer after considering the above and giving yourself enough time to absorb it. I'd love to hear a follow up comment from you about how it feels a month from now!
At least, that's my current thoughts on this, er, topic.
As usual, Raiph's answer is correct. I only add a small example that proofs what he says.
If you change the example to this:
my $a = "AABBCCBGG";
say join "\n", do for $a.comb.squish {
say "Pre-s/// $_";
$a ~~ s/^{say "Checking $_"} ($_+) //;
}
It will print
Pre-s/// A
Checking AABBCCBGG
$a is
Pre-s/// B
Checking
And then hang. Before entering the smartmatch, it holds the loop variable, but as soon as it's in the smarmatch, it changes to whatever is being smartmatched, and it's substituting the whole string by nothing, so since $a
is the null string in the second iteration, it hangs up.
Conclusion: use the topic variable only if you're very sure it's not being used elsewhere.