My original plan was to use two once {next}
blocks to skip the first two lines in a file (here emulating a as a multiline string):
for "A\nB\nC\n".lines() -> $line {
once {next}
once {next}
put $line;
}
But it only skipped one iteration instead of two, outputting the following:
B
C
Instead of what I expected:
C
Apparently a single once {next}
somehow cancels all remaining once
blocks in the same scope:
my $guard = 3;
loop {
last if $guard-- <= 0;
once { next };
once { put 'A: once ' };
once { put 'A: once again' };
put 'A: many ';
}
$guard = 3;
loop {
last if $guard-- <= 0;
once { put 'B: once ' };
once { next };
once { put 'B: once again' };
put 'B: many ';
}
$guard = 3;
loop {
last if $guard-- <= 0;
once { put 'C: once ' };
once { put 'C: once again' };
once { next };
put 'C: many ';
}
Outputting:
A: many
A: many
B: once
B: many
B: many
C: once
C: once again
C: many
C: many
(Example code here is a modified version of code at https://docs.raku.org/language/control#once).
Is this a bug or am I misunderstanding once {next}
?
The once
construct semantics are associated with closure clones; since for
is defined in terms of map
, we can think of the block of the for
loop being like a closure that is cloned once per loop, and that clone used for all iterations of the loop. The running of once
blocks is done only on the first invocation of that closure clone. That is to say, it's a property at the level of the closure, not one of the once
block itself.
The very same semantics apply to state
variable initializers, which are defined in the same way (that is, they have once
semantics). Therefore, this this also exhibits the same behavior:
for "A\nB\nC\n".lines() -> $line {
state $throwaway-a = next;
state $throwaway-b = next; # this `next` never runs
put $line;
}
Alternative semantics could have been chosen, however a per-once
(and so per-state
variable) indicator would imply an extra piece of state is needed for each of them.
So far as the original problem goes, a clearer solution would be:
for "A\nB\nC\n".lines().skip(2) -> $line {
put $line;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With