Skip to content

Commit 77374a0

Browse files
authored
Document interpolation-of-anon-state-vars as a trap
Found 6 or 7 cases of this bug in the ecosystem
1 parent 46384a1 commit 77374a0

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

doc/Language/traps.pod6

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,72 @@ say "Result2 is { $result2.^name }"; # OUTPUT: «Result2 is Any␤»
7878
7979
A L<C<Match> will be C<Nil>|https://docs.perl6.org/language/regexes#Literals> if it finds nothing; however it assigning C<Nil> to C<$result2> above will result in its default value, which is C<Any> as shown.
8080
81+
=head2 Using a block to interpolate anon state vars
82+
83+
The programmer intended for the code to count the number of times the routine
84+
is called, but the counter is not increasing:
85+
86+
=begin code
87+
sub count-it { say "Count is {$++}" }
88+
count-it;
89+
count-it;
90+
91+
# OUTPUT:
92+
# Count is 0
93+
# Count is 0
94+
=end code
95+
96+
When it comes to state variables, the block in which the vars are declared gets
97+
cloned—and vars get initialized anew—whenever that block's block is re-entered.
98+
This lets constructs like the one below behave appropriately: the state variable
99+
inside the loop gets initialized anew each time the sub is called:
100+
101+
=begin code
102+
sub count-it {
103+
for ^3 {
104+
state $count = 0;
105+
say "Count is $count";
106+
$count++;
107+
}
108+
}
109+
110+
count-it;
111+
say "…and again…";
112+
count-it;
113+
=end code
114+
115+
# OUTPUT:
116+
# Count is 0
117+
# Count is 1
118+
# Count is 2
119+
# …and again…
120+
# Count is 0
121+
# Count is 1
122+
# Count is 2
123+
124+
The same layout exists in our buggy program. The C<{ }> inside a double-quoted
125+
string isn't merely an interpolation to execute a piece of code. It's actually
126+
its own block, which is just as in the example above gets cloned each time the
127+
sub is entered, re-initializing our state variable. To get the right count,
128+
we need to get rid of that inner block, using a scalar contextualizer to
129+
interpolate our piece of code instead:
130+
131+
=begin code
132+
sub count-it { say "Count is $($++)" }
133+
count-it;
134+
count-it;
135+
136+
# OUTPUT:
137+
# Count is 0
138+
# Count is 1
139+
=end code
140+
141+
Alternatively, you can also use the L<concatenation operator|/routine/~> instead:
142+
143+
=begin code
144+
sub count-it { say "Count is " ~ $++ }
145+
=end code
146+
81147
=head1 Blocks
82148
83149
=head2 Beware of empty "blocks"

0 commit comments

Comments
 (0)