michał “phoe” herda
TRANSCRIPT
2
• We need means of unwinding and protecting against unwinds
3
• We need means of unwinding and protecting against unwinds
4
• We need means of unwinding and protecting against unwinds• We can implement all of CL-specific control flow with this!
5
• We need means of unwinding and protecting against unwinds• We can implement all of CL-specific control flow with this!
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
6
• We need means of unwinding and protecting against unwinds• We can implement all of CL-specific control flow with this!
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
7
• This includes non-local jumps(a secret Common Lisp feature)
• We need means of unwinding and protecting against unwinds• We can implement all of CL-specific control flow with this!
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
8
• This includes non-local jumps(a secret Common Lisp feature)
• This includes loops• This includes switches• This includes error handling• This includes restart handling
• We need means of unwinding and protecting against unwinds• We can implement all of CL-specific control flow with this!
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
9
• This includes non-local jumps(a secret Common Lisp feature)
• This includes loops• This includes switches• This includes error handling• This includes restart handling• The above four groups
are implemented in Common Lisp itself
10
• Software engineer at Ericsson (C/C++/Erlang)
11
• Software engineer at Ericsson (C/C++/Erlang)
• Common Lisp enthusiast (#lisp, Lisp Discord, Reddit)
12
• Software engineer at Ericsson (C/C++/Erlang)
• Common Lisp enthusiast (#lisp, Lisp Discord, Reddit)• Author of The Common Lisp Condition System (Apress, 2020)
13
• Software engineer at Ericsson (C/C++/Erlang)
• Common Lisp enthusiast (#lisp, Lisp Discord, Reddit)• Author of The Common Lisp Condition System (Apress, 2020)
• Somewhat capable of writing other programming languages
14
• Software engineer at Ericsson (C/C++/Erlang)
• Common Lisp enthusiast (#lisp, Lisp Discord, Reddit)• Author of The Common Lisp Condition System (Apress, 2020)
• Somewhat capable of writing other programming languages
• I kinda like the topic of control flow
15
• I kinda like the topic of control flow
16
• I kinda like the topic of control flow
17
18
19
20
21
22
23
24
foo()
bar()
baz()
25
foo()
bar()
baz()
1/0
26
foo()
bar()
baz()
1/0
ArithmeticException
27
foo()
bar()
baz()
1/0
ArithmeticException
28
foo()
bar()
baz()
1/0
ArithmeticException
29
foo()
bar()
baz()
1/0
ArithmeticException
30
foo()
bar()
baz()
1/0
catch
ArithmeticException
31
foo()
bar()
baz()
1/0
catch
32
foo()
bar()
33
foo()
bar()
... // execution continues
34
35
36
37
38
(foo)
(bar)
(baz)
39
(foo)
(bar)
(baz)
(/ 1 0)
40
(foo)
(bar)
(baz)
(/ 1 0)division-by-zero
41
(foo)
(bar)
(baz)
(/ 1 0)division-by-zero
42
(foo)
(bar)
(baz)
(/ 1 0)division-by-zero
43
(foo)
(bar)
(baz)
(/ 1 0)division-by-zero
44
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
45
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
(signal ...)
46
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
(signal ...)
handler-3
handler-2
handler-1
47
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
(signal ...)
handler-3
handler-2
handler-1
handler-1
48
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
(signal ...)
handler-3
handler-2
handler-1
handler-2
49
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
(signal ...)
handler-3
handler-2
handler-1
handler-3
50
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
(signal ...)
handler-3
handler-2
handler-1
51
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
52
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
(invoke-debugger ...)
53
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
(invoke-debugger ...)
54
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
(invoke-debugger ...)
55
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
handler-2
handler-3
handler-2
handler-1
division-by-zero
56
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
handler-2
handler-3
handler-2
handler-1
57
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
handler-2
handler-3
handler-2
handler-1
non-local jump
58
(foo)
59
(foo)
... // execution continues
60
(foo)
... // execution continues
61
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
(invoke-debugger ...)
62
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
(invoke-debugger ...)
restart-1restart-2
restart-4
restart-3
63
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
(invoke-debugger ...)
“Return 42 instead.”“Query the user for new numbers.”
“Abort and return to toplevel.”
“Try opening another file.”
64
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
(invoke-debugger ...)
“Return 42 instead.”“Query the user for new numbers.”
“Abort and return to toplevel.”
“Try opening another file.”
?
?
??
?
65
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
(invoke-debugger ...)
“Return 42 instead.”“Query the user for new numbers.”
“Abort and return to toplevel.”
“Try opening another file.”
division-by-zero
66
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
division-by-zero
67
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
handler-2
handler-3
handler-2
handler-1
division-by-zero
68
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
handler-2
handler-3
handler-2
handler-1
division-by-zero
“Try opening another file.”
69
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
handler-2
handler-3
handler-2
handler-1
division-by-zero
“Try opening another file.”
restart-fn
70
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
handler-2
handler-3
handler-2
handler-1
division-by-zero
“Try opening another file.”
restart-fn
non-localjump
71
(foo)
(bar)
72
(foo)
(bar)
... // execution continues
73
74
(foo)
(bar)
(baz)
(quux)
75
(foo)
(bar)
(baz)
(quux)some-condition
76
(foo)
(bar)
(baz)
(quux)some-condition
(signal ...)
77
(foo)
(bar)
(baz)
(quux)some-condition
handler-3
handler-2
handler-1
(signal ...)
78
(foo)
(bar)
(baz)
(quux)some-condition
handler-3
handler-2
handler-1
(signal ...)
handler-1
79
(foo)
(bar)
(baz)
(quux)some-condition
handler-3
handler-2
handler-1
(signal ...)
handler-2
80
(foo)
(bar)
(baz)
(quux)some-condition
handler-3
handler-2
handler-1
(signal ...)
handler-3
81
(foo)
(bar)
(baz)
(quux)some-condition
handler-3
handler-2
handler-1
(signal ...)
82
(foo)
(bar)
(baz)
(quux)some-condition
handler-3
handler-2
handler-1
¯\_(ツ)_/¯
83
(foo)
(bar)
(baz)
(quux)
84
(foo)
(bar)
(baz)
(quux)
... // execution continues
85
• Construct the exception object
86
• Construct the exception object• Unwind the stack immediately
• Stop unwinding when something catches the exception
87
• Construct the exception object• Unwind the stack immediately
• Stop unwinding when something catches the exception• Continue execution from that point
88
89
• Construct the condition object
90
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?
91
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?
92
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code
93
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart
94
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return
95
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point
96
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point• Maybe there are no handlers
97
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point• Maybe there are no handlers• Maybe she’s born with it
98
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point• Maybe there are no handlers• Maybe she’s born with it• Maybe it’s Maybelline™
99
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point• Maybe there are no handlers• Maybe she’s born with it• Maybe it’s Maybelline™
• If there was no transfer of control, return• ...and maybe enter the debugger to halt the program
100
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point• Maybe there are no handlers• Maybe she’s born with it• Maybe it’s Maybelline™
• If there was no transfer of control, return• ...and maybe enter the debugger to halt the program
101
• signaling = a dynamically scoped hooking mechanism
• progress bars• message passing• calling asynchronous code• etc..
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point• Maybe there are no handlers• Maybe she’s born with it• Maybe it’s Maybelline™
• If there was no transfer of control, return• ...and maybe enter the debugger to halt the program
102
• signaling = a dynamically scoped hooking mechanism
• progress bars• message passing• calling asynchronous code• etc..
• restarts = a dynamically scoped mechanism of choices
• context-dependent actionsfor interactive programming
• context-dependent meansof automated error recovery(e.g. when parsing incomplete source code)
• etc..
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point• Maybe there are no handlers• Maybe she’s born with it• Maybe it’s Maybelline™
• If there was no transfer of control, return• ...and maybe enter the debugger to halt the program
103
• signaling = a dynamically scoped hooking mechanism
• progress bars• message passing• calling asynchronous code• etc..
• restarts = a dynamically scoped mechanism of choices
• context-dependent actionsfor interactive programming
• context-dependent meansof automated error recovery(e.g. when parsing incomplete source code)
• etc..
104
105
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point• Maybe there are no handlers• Maybe she’s born with it• Maybe it’s Maybelline™
• If there was no transfer of control, return• ...and maybe enter the debugger to halt the program
106
• signaling = a dynamically scoped hooking mechanism
• progress bars• message passing• calling asynchronous code• etc..
• restarts = a dynamically scoped mechanism of choices
• context-dependent actionsfor interactive programming
• context-dependent meansof automated error recovery(e.g. when parsing incomplete source code)
• etc..
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point• Maybe there are no handlers• Maybe she’s born with it• Maybe it’s Maybelline™
• If there was no transfer of control, return• ...and maybe enter the debugger to halt the program
107
• signaling = a dynamically scoped hooking mechanism
• progress bars• message passing• calling asynchronous code• etc..
• restarts = a dynamically scoped mechanism of choices
• context-dependent actionsfor interactive programming
• context-dependent meansof automated error recovery(e.g. when parsing incomplete source code)
• etc..
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point• Maybe there are no handlers• Maybe she’s born with it• Maybe it’s Maybelline™
• If there was no transfer of control, return• ...and maybe enter the debugger to halt the program
108
• signaling = a dynamically scoped hooking mechanism
• progress bars• message passing• calling asynchronous code• etc..
• restarts = a dynamically scoped mechanism of choices
• context-dependent actionsfor interactive programming
• context-dependent meansof automated error recovery(e.g. when parsing incomplete source code)
• etc..
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point• Maybe there are no handlers• Maybe she’s born with it• Maybe it’s Maybelline™
• If there was no transfer of control, return• ...and maybe enter the debugger to halt the program
109
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
handler-2
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point• Maybe there are no handlers• Maybe she’s born with it• Maybe it’s Maybelline™
• If there was no transfer of control, return• ...and maybe enter the debugger to halt the program
110
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
handler-2
• Construct the condition object• Call handlers from the stack in order
• What do the handlers do?• Maybe execute some code• Maybe invoke a restart• Maybe do nothing and return• Maybe unwind the stack to a predefined point• Maybe there are no handlers• Maybe she’s born with it• Maybe it’s Maybelline™
• If there was no transfer of control, return• ...and maybe enter the debugger to halt the program
111
(foo)
(bar)
(baz)
(/ 1 0)
(error ...)
handler-2
112
• if
(if (foo) (bar) (baz))
113
• if• tagbody/go
(tagbody 10 (print “hello”) 20 (go 10))
114
(block my-block (...) (... (return-from my-block 42)) (...))
115
• if• tagbody/go• block/return-from
(catch ‘quux (...) (... (foo)) (...)))
(defun foo () (throw ‘quux 42))
116
• if• tagbody/go• block/return-from• catch/throw
• if• tagbody/go• block/return-from• catch/throw• unwind-protect
(let ((thing (make-thing))) (unwind-protect (frob thing) (cleanup thing)))
117
(let ((fn (lambda ...)) (args ...)) (apply fn 1 2 3 args))
118
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(let ((fn (lambda ...)) (args ...)) (apply fn 1 2 3 args))
(let ((fn (lambda ...))) (funcall fn 1 2 3))
119
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply ; and funcall
120
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
121
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
122
(let ((x 42)) (lambda () x))
123
(let ((x 42)) (lambda () x));; #<FUNCTION (LAMBDA ())>
124
(let ((x 42)) (lambda () x));; #<FUNCTION (LAMBDA ())>
(funcall *) ; (funcall #<FUNCTION (LAMBDA ())>)
125
(let ((x 42)) (lambda () x));; #<FUNCTION (LAMBDA ())>
(funcall *) ; (funcall #<FUNCTION (LAMBDA ())>);; => 42
126
(let ((x 42)) (lambda () x));; #<FUNCTION (LAMBDA ())>
(funcall *) ; (funcall #<FUNCTION (LAMBDA ())>);; => 42
;; but we can close over more;; than just lexical variables!
127
128
(let ((x 42)) (lambda () x));; #<FUNCTION (LAMBDA ())>
(funcall *) ; (funcall #<FUNCTION (LAMBDA ())>);; => 42
;; but we can close over more;; than just lexical variables!
129
(defun foo (x) (funcall x))
130
(defun foo (x) (funcall x))
(defun bar () ; block bar ...)
131
(defun foo (x) (funcall x))
(defun bar () (let ((fn (lambda () (return-from bar 42)))) ...))
132
(defun foo (x) (funcall x))
(defun bar () (let ((fn (lambda () (return-from bar 42)))) (foo fn)))
133
(defun foo (x) (funcall x))
(defun bar () (let ((fn (lambda () (return-from bar 42)))) (foo fn)))
(bar)
134
(defun foo (x) (funcall x))
(defun bar () (let ((fn (lambda () (return-from bar 42)))) (foo fn)))
(bar)(bar)
135
(defun foo (x) (funcall x))
(defun bar () (let ((fn (lambda () (return-from bar 42)))) (foo fn)))
(bar)(bar)
(foo)
136
(defun foo (x) (funcall x))
(defun bar () (let ((fn (lambda () (return-from bar 42)))) (foo fn)))
(bar)(bar)
(foo)
(lambda () ...)
137
(defun foo (x) (funcall x))
(defun bar () (let ((fn (lambda () (return-from bar 42)))) (foo fn)))
(bar)(bar)
(foo)
(lambda () ...)
138
(defun foo (x) (funcall x))
(defun bar () (let ((fn (lambda () (return-from bar 42)))) (foo fn)))
(bar)(bar)
(foo)
(lambda () ...)
139
(defun foo (x) (funcall x))
(defun bar () (let ((fn (lambda () (return-from bar 42)))) (foo fn)))
(bar);; => 42
140
(defun foo (x) (funcall x))
(defun bar () (let ((fn (lambda () (return-from bar 42)))) (foo fn)))
(bar);; => 42
141
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
142
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
143
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)
144
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)
145
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)
1
!
146
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)
147
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)1
?
?
?
148
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)1
?
?
?
149
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)1
2?
?
?
!
150
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
151
• if• tagbody/go ; 1-phase unwind (no search)• block/return-from ; 1-phase unwind (no search)• catch/throw ; 2-phase unwind (search)• unwind-protect• lambda/apply
152
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
153
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
154
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• All other CL control flow operators are derivatives of those primitives
155
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• All other CL control flow operators are derivatives of those primitives• loops (do, dolist, loop, ...)
156
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• All other CL control flow operators are derivatives of those primitives• loops (do, dolist, loop, ...)• switches (cond, case, typecase, ...)
157
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• All other CL control flow operators are derivatives of those primitives• loops (do, dolist, loop, ...)• switches (cond, case, typecase, ...)• error handling (handler-case, ...)
158
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• All other CL control flow operators are derivatives of those primitives• loops (do, dolist, loop, ...)• switches (cond, case, typecase, ...)• error handling (handler-case, ...)• restarts (restart-case, ...)
159
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• All other CL control flow operators are derivatives of those primitives• loops (do, dolist, loop, ...)• switches (cond, case, typecase, ...)• error handling (handler-case, ...)• restarts (restart-case, ...)
• This list includes use cases that are not related to exception handling
160
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• All other CL control flow operators are derivatives of those primitives• loops (do, dolist, loop, ...)• switches (cond, case, typecase, ...)• error handling (handler-case, ...)• restarts (restart-case, ...)
• This list includes use cases that are not related to exception handling
161
• Control flow ≠ exception handling
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• All other CL control flow operators are derivatives of those primitives• loops (do, dolist, loop, ...)• switches (cond, case, typecase, ...)• error handling (handler-case, ...)• restarts (restart-case, ...)
• This list includes use cases that are not related to exception handling
162
• Control flow ≠ exception handling
163
• Control flow ≠ exception handling
• Do not conflate unwinding with throwing exceptions
164
• Control flow ≠ exception handling
• Do not conflate unwinding with throwing exceptions• Throwing exceptions is a subset of control flow
165
• Control flow ≠ exception handling
• Do not conflate unwinding with throwing exceptions• Throwing exceptions is a subset of control flow• Throwing exceptions is not synonymous with unwinding
166
• Control flow ≠ exception handling
• Do not conflate unwinding with throwing exceptions• Throwing exceptions is a subset of control flow• Throwing exceptions is not synonymous with unwinding• Throwing exceptions is not a primitive operation
167
• Control flow ≠ exception handling
• Do not conflate unwinding with throwing exceptions• Throwing exceptions is a subset of control flow• Throwing exceptions is not synonymous with unwinding• Throwing exceptions is not a primitive operation
• Proofs: Common Lisp, Dylan, Smalltalk
168
• Control flow ≠ exception handling
169
but wait hold on for just one moment
170
Appendix A
Proving one-phase unwind in TAGBODY and BLOCK
171
• if• tagbody/go ; 1-phase unwind (no search)• block/return-from ; 1-phase unwind (no search)• catch/throw ; 2-phase unwind (search)• unwind-protect• lambda/apply
172
• if• tagbody/go ; 1-phase unwind (no search)• block/return-from ; 1-phase unwind (no search)• catch/throw ; 2-phase unwind (search)• unwind-protect• lambda/apply
173
174
• if• tagbody/go ; 1-phase unwind (no search)• block/return-from ; 1-phase unwind (no search)• catch/throw ; 2-phase unwind (search)• unwind-protect• lambda/apply
(block foo (lambda () (return-from foo)))
175
• if• tagbody/go ; 1-phase unwind (no search)• block/return-from ; 1-phase unwind (no search)• catch/throw ; 2-phase unwind (search)• unwind-protect• lambda/apply
(let ((fn (block foo (lambda () (return-from foo))))) (funcall fn)); ...?
176
• if• tagbody/go ; 1-phase unwind (no search)• block/return-from ; 1-phase unwind (no search)• catch/throw ; 2-phase unwind (search)• unwind-protect• lambda/apply
(let ((fn (block foo (lambda () (return-from foo))))) (funcall fn)); ERROR: Condition CONTROL-ERROR; was signaled.
177
• if• tagbody/go ; 1-phase unwind (no search)• block/return-from ; 1-phase unwind (no search)• catch/throw ; 2-phase unwind (search)• unwind-protect• lambda/apply
• if• tagbody/go ; 1-phase unwind (no search)• block/return-from ; 1-phase unwind (no search)• catch/throw ; 2-phase unwind (search)• unwind-protect• lambda/apply (let ((fn (block foo
(lambda () (return-from foo))))) (funcall fn)); ERROR: Condition CONTROL-ERROR; was signaled.
178
• if• tagbody/go ; 1-phase unwind (no search)• block/return-from ; 1-phase unwind (no search)• catch/throw ; 2-phase unwind (search)• unwind-protect• lambda/apply (let ((fn (block foo
(lambda () (return-from foo))))) (funcall fn)); ERROR: Condition CONTROL-ERROR; was signaled.
179
? ?
(block foo (lambda () (return-from foo)))
180
(block foo ...)
181
(let ((return-valid-p t)) (unwind-protect (%unwind-tag foo ...) (setf return-valid-p nil)))
182
(let ((return-valid-p t)) (unwind-protect (%unwind-tag foo ...) ;; let’s expand the lambda! (setf return-valid-p nil)))
183
(let ((return-valid-p t)) (unwind-protect (%unwind-tag foo (lambda () (if return-valid-p (%1-phase-unwind-to-tag foo) (error ‘control-error)))) (setf return-valid-p nil)))
184
(let ((return-valid-p t)) (unwind-protect (%unwind-tag foo (lambda () (if return-valid-p (%1-phase-unwind-to-tag foo) (error ‘control-error)))) (setf return-valid-p nil)))
185
(let ((return-valid-p t)) (unwind-protect (%unwind-tag foo (lambda () (if return-valid-p (%1-phase-unwind-to-tag foo) (error ‘control-error)))) (setf return-valid-p nil)))
186
(let ((return-valid-p t)) (unwind-protect (%unwind-tag foo (lambda () (if return-valid-p (%1-phase-unwind-to-tag foo) (error ‘control-error)))) (setf return-valid-p nil)))
;; similar validation scheme applies for TAGBODY/GO
187
Appendix B
Describing UNWIND-PROTECT
188
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
189
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
190
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
191
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)
192
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)
193
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)
194
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)
195
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)
196
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)
197
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
(foo)
(bar)
(baz)
(quux)
(frob)
198
Appendix C
Common Lisp condition system without Common Lisp
(this is the last one I promise)199
200
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
201
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• if• tagbody/go• block/return-from• catch/throw• try/finally• new/.apply()• throw exception
202
203
204
205• Can we port the condition system to Java?
206• Can we port CL control flow to Java?
207• Can we port CL control flow to Java?
208
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• if• tagbody/go• block/return-from• catch/throw• try/finally• new/.apply()• throw exception
209
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• if• tagbody/go• block/return-from• catch/throw• try/finally• new/.apply()• throw exception
210
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• if• tagbody/go• block/return-from• catch/throw• try/finally• new/.apply()• throw exception
“I suppose it is tempting, if the only tool you have is a hammer,to treat everything as if it were a nail.”
--- Abraham H. Maslow
211
• if• tagbody/go• block/return-from• catch/throw• unwind-protect• lambda/apply
• if• tagbody/go• block/return-from• catch/throw• try/finally• new/.apply()• throw exception
https://github.com/phoe/cafe-latte
212
yes, it’s seriously the end this time
213