1Syntax::Keyword::Defer(U3s)er Contributed Perl DocumentatSiyonntax::Keyword::Defer(3)
2
3
4
6 "Syntax::Keyword::Defer" - execute code when leaving a block
7
9 use Syntax::Keyword::Defer;
10
11 {
12 my $dbh = DBI->connect( ... ) or die "Cannot connect";
13 defer { $dbh->disconnect; }
14
15 my $sth = $dbh->prepare( ... ) or die "Cannot prepare";
16 defer { $sth->finish; }
17
18 ...
19 }
20
22 This module provides a syntax plugin that implements a block which
23 executes when the containing scope has finished.
24
25 It similar to features provided by other languages; Swift, Zig, Jai,
26 Nim and Odin all provide this. Note that while Go also provides a
27 "defer" keyword, the semantics here are not the same. Go's version
28 defers until the end of the entire function, rather than the closest
29 enclosing scope as is common to most other languages, and this module.
30
31 The operation can be considered a little similar to an "END" block, but
32 with the following key differences:
33
34 • A "defer" block runs at the time that execution leaves the block it
35 is declared inside, whereas an "END" block runs at the end time of
36 the entire program regardless of its location.
37
38 • A "defer" block is invoked at the time its containing scope has
39 finished, which means it might run again if the block is entered
40 again later in the program. An "END" block will only ever run once.
41
42 • A "defer" block will only take effect if execution reaches the line
43 it is declared on; if the line is not reached then nothing happens.
44 An "END" block will always be invoked once declared, regardless of
45 the dynamic extent of execution at runtime.
46
47 "defer" blocks are primarily intended for cases such as resource
48 finalisation tasks that may be conditionally required.
49
50 For example in the synopsis code, after normal execution the statement
51 handle will be finished using the "$sth->finish" method, then the
52 database will be disconnected with "$dbh->disconnect". If instead the
53 prepare method failed then the database will still be disconnected, but
54 there is no need to finish with the statement handle as the second
55 "defer" block was never encountered.
56
58 defer
59 defer {
60 STATEMENTS...
61 }
62
63 The "defer" keyword introduces a block which runs its code body at the
64 time that its immediately surrounding code block finishes.
65
66 When the "defer" statement is encountered, the body of the code block
67 is pushed to a queue of pending operations, which is then flushed when
68 the surrounding block finishes for any reason - either by implicit
69 fallthrough, or explicit termination by "return", "die" or any of the
70 loop control statements "next", "last" or "redo".
71
72 sub f
73 {
74 defer { say "The function has now returned"; }
75 return 123;
76 }
77
78 If multiple "defer" statements appear within the same block, they are
79 pushed to the queue in LIFO order; the last one encountered is the
80 first one to be executed.
81
82 {
83 defer { say "This happens second"; }
84 defer { say "This happens first"; }
85 }
86
87 A "defer" block will only take effect if the statement itself is
88 actually encountered during normal execution. This is in direct
89 contrast to an "END" phaser which always occurs. This makes it ideal
90 for handling finalisation of a resource which was created on a nearby
91 previous line, where the code to create it might have thrown an
92 exception instead. Because the exception skipped over the "defer"
93 statement, the code body does not need to run.
94
95 my $resource = Resource->open( ... );
96 defer { $resource->close; }
97
98 Unlike as would happen with e.g. a "DESTROY" method on a guard object,
99 any exceptions thrown from a "defer" block are still propagated up to
100 the caller in the usual way.
101
102 use Syntax::Keyword::Defer;
103
104 sub f
105 {
106 my $count = 0;
107 defer { $count or die "Failed to increment count"; }
108
109 # some code here
110 }
111
112 f();
113
114 $ perl example.pl
115 Failed to increment count at examples.pl line 6.
116
117 Because a "defer" block is a true block (e.g. in the same way something
118 like an "if () {...}" block is), rather than an anonymous sub, it does
119 not appear to "caller()" or other stack-inspection tricks. This is
120 useful for calling "croak()", for example.
121
122 sub g
123 {
124 my $count = 0;
125 defer { $count or croak "Expected some items"; }
126
127 $count++ for @_;
128 }
129
130 Here, "croak()" will correctly report the caller of the "g()" function,
131 rather than appearing to be called from an "__ANON__" sub invoked at
132 the end of the function itself.
133
135 This module contains a unit test file copied and edited from my core
136 perl branch to provide the same syntax. Several test cases are
137 currently commented out because this implementation does not yet handle
138 them:
139
140 • Try to fix the double-exception test failure on Perl versions
141 before v5.20. (Test currently skipped on those versions)
142
143 • Permit the use of "goto" or "next/last/redo" within "defer" blocks,
144 provided it does not jump to a target outside.
145
146 E.g. the following ought to be permitted, but currently is not:
147
148 defer {
149 foreach my $item (@items) {
150 $item > 5 or next;
151 ...
152 }
153 }
154
155 • Try to detect and forbid nonlocal flow control ("goto",
156 "next/last/redo") from leaving the "defer" block.
157
158 E.g. currently the following will crash the interpreter:
159
160 sub func { last ITEM }
161
162 ITEM: foreach(1..10) {
163 say;
164 defer { func() }
165 }
166
168 Paul Evans <leonerd@leonerd.org.uk>
169
170
171
172perl v5.34.0 2022-02-21 Syntax::Keyword::Defer(3)