Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use of implicit parameter in for-loop causes hang

Tags:

raku

Consider the following code

my $a = "AABBCCBGG";
say join "\n", do for $a.comb.squish {
  $a ~~ s/^ ($_+) //;
}

versus

my $a = "AABBCCBGG";
say join "\n", do for $a.comb.squish -> $b {
  $a ~~ s/^ ($b+) //;
}

The first hangs forever while the last executes as expected. Is this an error or is there some finer detail while using the implicit $_ that I don't understand? Using Rakudo Star 2019.03.01.

like image 428
Jo Christian Oterhals Avatar asked Aug 12 '19 13:08

Jo Christian Oterhals


1 Answers

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 if foo 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 where bar is a sub expecting an argument and we want it to get foo.

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.

like image 200
raiph Avatar answered Sep 28 '22 02:09

raiph