Skip to content

Commit 7a74e1e

Browse files
committed
Doc lonely LEAVE block execution trap
Resolves #1539.
1 parent 80d1de7 commit 7a74e1e

File tree

1 file changed

+29
-0
lines changed

1 file changed

+29
-0
lines changed

doc/Language/traps.pod6

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,6 +1109,7 @@ $a.sayit; # OUTPUT: «hi␤»
11091109
my $b = A.new;
11101110
$b.sayit; # nothing
11111111
1112+
11121113
=head2 C<LEAVE> phaser and C<exit>
11131114
11141115
Using L«C<LEAVE>|/syntax/LEAVE» phaser to perform graceful resource
@@ -1145,5 +1146,33 @@ Closing the resource gracefully
11451146
A call to C<exit> is part of normal operation for many programs, so
11461147
beware unintentional combination of C<LEAVE> phasers and C<exit> calls.
11471148
1149+
=head2 C<LEAVE> phaser may run sooner than you think
1150+
1151+
You should always expect the C<LEAVE> phaser to execute before
1152+
I<anything> else in the block was executed.
1153+
1154+
Here is an example:
1155+
1156+
=begin code
1157+
sub foo($ where ‘abc’) {
1158+
my $x = 42;
1159+
LEAVE say $x.Int; # ← WRONG; assumes that $x is not Nil
1160+
}
1161+
say foo ‘hello’; # OUTPUT: «No such method 'Int' for invocant of type 'Any'␤»
1162+
=end code
1163+
1164+
You may think that there is no way C<my $x = 42> can fail, and
1165+
therefore C<$x> will always be defined in the C<LEAVE> block. But that
1166+
is simply not the case. There is no guarantee that anything will
1167+
executed at all, which is what happens when type constraints are
1168+
involved.
1169+
1170+
The right way to do it is to I<always> check that whatever you use in
1171+
your C<LEAVE> block is defined:
1172+
1173+
=begin code :skip-test
1174+
LEAVE say .Int with $x
1175+
=end code
1176+
11481177
=end pod
11491178
# vim: expandtab shiftwidth=4 ft=perl6

0 commit comments

Comments
 (0)