1Syntax::Keyword::Defer(U3spemr)Contributed Perl DocumentSaytnitoanx::Keyword::Defer(3pm)
2
3
4

NAME

6       "Syntax::Keyword::Defer" - execute code when leaving a block
7

SYNOPSIS

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

DESCRIPTION

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

KEYWORDS

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       However, if a "defer" block is being run because of exceptional return
118       of its scope, any further exceptions it attempts to raise are turned
119       into warnings.  This ensures that the original exception which caused
120       the stack-unwind to run the block in the first place does not get
121       overwritten on the way.
122
123       Because a "defer" block is a true block (e.g. in the same way something
124       like an "if () {...}" block is), rather than an anonymous sub, it does
125       not appear to caller() or other stack-inspection tricks. This is useful
126       for calling croak(), for example.
127
128          sub g
129          {
130             my $count = 0;
131             defer { $count or croak "Expected some items"; }
132
133             $count++ for @_;
134          }
135
136       Here, croak() will correctly report the caller of the g() function,
137       rather than appearing to be called from an "__ANON__" sub invoked at
138       the end of the function itself.
139

TODO

141       This module contains a unit test file copied and edited from my core
142       perl branch to provide the same syntax. Several test cases are
143       currently commented out because this implementation does not yet handle
144       them:
145
146       •   Detection logic of defer-during-throw is currently based on the
147           truth of the "ERRSV" ($@), which means it is liable to false
148           positives. There may not be much that can be done about this.
149
150       •   Try to fix the double-exception test failure on Perl versions
151           before v5.20.  (Test currently skipped on those versions)
152
153       •   Try to detect and forbid nonlocal flow control ("goto",
154           "next/last/redo") from leaving the "defer" block.
155
156           E.g. currently the following will crash the interpreter:
157
158              sub func { last ITEM }
159
160              ITEM: foreach(1..10) {
161                 say;
162                 defer { func() }
163              }
164

AUTHOR

166       Paul Evans <leonerd@leonerd.org.uk>
167
168
169
170perl v5.38.0                      2023-07-21       Syntax::Keyword::Defer(3pm)
Impressum