]> gitweb.factorcode.org Git - factor.git/blob - core/continuations/continuations-docs.factor
continuations[-docs]: add the finally word
[factor.git] / core / continuations / continuations-docs.factor
1 USING: continuations.private help.markup help.syntax kernel
2 kernel.private lexer namespaces quotations sequences vectors ;
3 IN: continuations
4
5 ARTICLE: "errors-restartable" "Restartable errors"
6 "Support for restartable errors is built on top of the basic error handling facility. The following words signals recoverable errors:"
7 { $subsections
8     throw-restarts
9     rethrow-restarts
10 }
11 "A utility word using the above:"
12 { $subsections
13     throw-continue
14 }
15 "The list of restarts from the most recently-thrown error is stored in a global variable:"
16 { $subsections restarts }
17 "To invoke restarts, use " { $link "debugger" } "." ;
18
19 ARTICLE: "errors-post-mortem" "Post-mortem error inspection"
20 "The most recently thrown error, together with the continuation at that point, are stored in a pair of global variables:"
21 { $subsections
22     error
23     error-continuation
24 }
25 "Developer tools for inspecting these values are found in " { $link "debugger" } "." ;
26
27 ARTICLE: "errors-anti-examples" "Common error handling pitfalls"
28 "When used correctly, exception handling can lead to more robust code with less duplication of error handling logic. However, there are some pitfalls to keep in mind."
29 { $heading "Anti-pattern #1: Ignoring errors" }
30 "The " { $link ignore-errors } " word should almost never be used. Ignoring errors does not make code more robust and in fact makes it much harder to debug if an intermittent error does show up when the code is run under previously unforseen circumstances. Never ignore unexpected errors; always report them to the user."
31 { $heading "Anti-pattern #2: Catching errors too early" }
32 "A less severe form of the previous anti-pattern is code that makes overly zealous use of " { $link recover } ". It is almost always a mistake to catch an error, log a message, and keep going. The only exception is network servers and other long-running processes that must remain running even if individual tasks fail. In these cases, place the " { $link recover } " as high up in the call stack as possible."
33 $nl
34 "In most other cases, " { $link cleanup } " should be used instead to handle an error and rethrow it automatically."
35 { $heading "Anti-pattern #3: Dropping and rethrowing" }
36 "Do not use " { $link recover } " to handle an error by dropping it and throwing a new error. By losing the original error message, you signal to the user that something failed without leaving any indication of what actually went wrong. Either wrap the error in a new error containing additional information, or rethrow the original error. A more subtle form of this is using " { $link throw } " instead of " { $link rethrow } ". The " { $link throw } " word should only be used when throwing new errors, and never when rethrowing errors that have been caught."
37 { $heading "Anti-pattern #4: Logging and rethrowing" }
38 "If you are going to rethrow an error, do not log a message. If you do so, the user will see two log messages for the same error, which will clutter logs without adding any useful information." ;
39
40 ARTICLE: "errors" "Exception handling"
41 "Support for handling exceptional situations such as bad user input, implementation bugs, and input/output errors is provided by a set of words built using continuations."
42 $nl
43 "Two words raise an error in the innermost error handler for the current dynamic extent:"
44 { $subsections
45     throw
46     rethrow
47 }
48 "Words for establishing an error handler:"
49 { $subsections
50     cleanup
51     recover
52     ignore-errors
53 }
54 "Syntax sugar for defining errors:"
55 { $subsections POSTPONE: ERROR: }
56 "Unhandled errors are reported in the listener and can be debugged using various tools. See " { $link "debugger" } "."
57 { $subsections
58     "errors-restartable"
59     "debugger"
60     "errors-post-mortem"
61     "errors-anti-examples"
62 }
63 "When Factor encounters a critical error, it calls the following word:"
64 { $subsections die } ;
65
66 ARTICLE: "continuations.private" "Continuation implementation details"
67 "A continuation is simply a tuple holding the contents of the five stacks:"
68 { $subsections
69     continuation
70     >continuation<
71 }
72 "The five stacks can be read and written:"
73 { $subsections
74     get-datastack
75     set-datastack
76     get-retainstack
77     set-retainstack
78     get-callstack
79     set-callstack
80     get-namestack
81     set-namestack
82     get-catchstack
83     set-catchstack
84 } ;
85
86 ARTICLE: "continuations" "Continuations"
87 "At any point in the execution of a program, the " { $emphasis "current continuation" } " represents the future of the computation."
88 $nl
89 "Words for working with continuations are found in the " { $vocab-link "continuations" } " vocabulary; implementation details are in " { $vocab-link "continuations.private" } "."
90 $nl
91 "Continuations can be reified with the following two words:"
92 { $subsections
93     callcc0
94     callcc1
95 }
96 "Another two words resume continuations:"
97 { $subsections
98     continue
99     continue-with
100 }
101 "Continuations as control-flow:"
102 { $subsections
103     attempt-all
104     with-return
105 }
106 "Continuations serve as the building block for a number of higher-level abstractions, such as " { $link "errors" } " and " { $link "threads" } "."
107 { $subsections "continuations.private" } ;
108
109 ABOUT: "continuations"
110
111 HELP: (get-catchstack)
112 { $values { "catchstack" "a vector of continuations" } }
113 { $description "Outputs the current catchstack." } ;
114
115 HELP: get-catchstack
116 { $values { "catchstack" "a vector of continuations" } }
117 { $description "Outputs a copy of the current catchstack." } ;
118
119 HELP: current-continuation
120 { $values { "continuation" continuation } }
121 { $description "Creates a continuation object from the current execution context." } ;
122
123 HELP: set-catchstack
124 { $values { "catchstack" "a vector of continuations" } }
125 { $description "Replaces the catchstack with a copy of the given vector." } ;
126
127 HELP: continuation
128 { $class-description "Reifies the current continuation from the point immediately after which the caller returns." } ;
129
130 HELP: >continuation<
131 { $values { "continuation" continuation } { "data" vector } { "call" vector } { "retain" vector } { "name" vector } { "catch" vector } }
132 { $description "Takes a continuation apart into its constituents." } ;
133
134 HELP: ifcc
135 { $values { "capture" { $quotation ( continuation -- ) } } { "restore" quotation } }
136 { $description "Reifies a continuation from the point immediately after which this word returns, and passes it to " { $snippet "capture" } ". When the continuation is restored, execution resumes and " { $snippet "restore" } " is called." } ;
137
138 { callcc0 continue callcc1 continue-with ifcc } related-words
139
140 HELP: callcc0
141 { $values { "quot" { $quotation ( continuation -- ) } } }
142 { $description "Applies the quotation to the current continuation, which is reified from the point immediately after which the caller returns. The " { $link continue } " word resumes the continuation." } ;
143
144 HELP: callcc1
145 { $values { "quot" { $quotation ( continuation -- ) } } { "obj" "an object provided when resuming the continuation" } }
146 { $description "Applies the quotation to the current continuation, which is reified from the point immediately after which the caller returns. The " { $link continue-with } " word resumes the continuation, passing a value back to the original execution context." } ;
147
148 HELP: continue
149 { $values { "continuation" continuation } }
150 { $description "Resumes a continuation reified by " { $link callcc0 } "." } ;
151
152 HELP: continue-with
153 { $values { "obj" "an object to pass to the continuation's execution context" } { "continuation" continuation } }
154 { $description "Resumes a continuation reified by " { $link callcc1 } ". The object will be placed on the data stack when the continuation resumes." } ;
155
156 HELP: error
157 { $description "Global variable holding most recently thrown error." }
158 { $notes "Only updated by " { $link throw } ", not " { $link rethrow } "." } ;
159
160 HELP: error-continuation
161 { $description "Global variable holding current continuation of most recently thrown error." }
162 { $notes "Only updated by " { $link throw } ", not " { $link rethrow } "." } ;
163
164 HELP: restarts
165 { $var-description "Global variable holding the set of possible restarts for the most recently thrown error." }
166 { $notes "Only updated by " { $link throw } ", not " { $link rethrow } "." } ;
167
168 HELP: throw
169 { $values { "error" object } }
170 { $description "Saves the current continuation in the " { $link error-continuation } " global variable and throws an error. Execution does not continue at the point after the " { $link throw } " call. Rather, the innermost catch block is invoked, and execution continues at that point." } ;
171
172 { cleanup recover finally } related-words
173
174 HELP: cleanup
175 { $values { "try" { $quotation ( ..a -- ..a ) } } { "cleanup-always" { $quotation ( ..a -- ..b ) } } { "cleanup-error" { $quotation ( ..b -- ..b ) } } }
176 { $description "Calls the " { $snippet "try" } " quotation. If no error is thrown, calls " { $snippet "cleanup-always" } " without restoring the data stack. If an error is thrown, restores the data stack, calls " { $snippet "cleanup-always" } " followed by " { $snippet "cleanup-error" } ", and rethrows the error." } ;
177
178 HELP: finally
179 { $values { "try" { $quotation ( ..a -- ..a ) } } { "cleanup-always" { $quotation ( ..a -- ..b ) } } }
180 { $description "Same as " { $link cleanup } ", but with empty " { $snippet "cleanup-error" } " quotation. Useful when some cleanup code needs to be run after the " { $snippet "try" } " quotation whether an error was thrown or not, but when nothing specific needs to be done about any errors." } ;
181
182 HELP: recover
183 { $values { "try" { $quotation ( ..a -- ..b ) } } { "recovery" { $quotation ( ..a error -- ..b ) } } }
184 { $description "Calls the " { $snippet "try" } " quotation. If an exception is thrown in the dynamic extent of the " { $snippet "try" } " quotation, restores the data stack and calls the " { $snippet "recovery" } " quotation to handle the error." } ;
185
186 HELP: ignore-error
187 { $values { "quot" quotation } { "check" quotation } }
188 { $description "Calls the quotation. If an exception is thrown which is matched by the 'check' quotation it is ignored. Otherwise the error is rethrown." } ;
189
190 HELP: ignore-error/f
191 { $values { "quot" quotation } { "check" quotation } }
192 { $description "Like " { $link ignore-error } ", but if a matched exception is thrown " { $link f } " is put on the stack." } ;
193
194 HELP: ignore-errors
195 { $values { "quot" quotation } }
196 { $description "Calls the quotation. If an exception is thrown in the dynamic extent of the quotation, restores the data stack and returns." }
197 { $notes "For safer alternatives to this word see " { $link ignore-error } " and " { $link ignore-error/f } "." } ;
198
199 HELP: in-callback?
200 { $values { "?" boolean } }
201 { $description "t if Factor is currently executing a callback." } ;
202
203 HELP: rethrow
204 { $values { "error" object } }
205 { $description "Throws an error without saving the current continuation in the " { $link error-continuation } " global variable. This is done so that inspecting the error stacks sheds light on the original cause of the exception, rather than the point where it was rethrown." }
206 { $notes
207     "This word is intended to be used in conjunction with " { $link recover } " to implement error handlers which perform an action and pass the error to the next outermost error handler."
208 }
209 { $examples
210     "The " { $link with-lexer } " word catches errors, annotates them with the current line and column number, and rethrows them:"
211     { $see with-lexer }
212 } ;
213
214 HELP: throw-restarts
215 { $values { "error" object } { "restarts" { $sequence { { $snippet "{ string object }" } " pairs" } } } { "restart" object } }
216 { $description "Throws a restartable error using " { $link throw } ". The " { $snippet "restarts" } " parameter is a sequence of pairs where the first element in each pair is a human-readable description and the second is an arbitrary object. If the error reaches the top-level error handler, the user will be presented with the list of possible restarts, and upon invoking one, execution will continue after the call to " { $link throw-restarts } " with the object associated to the chosen restart on the stack." }
217 { $examples
218     "Try invoking one of the two restarts which are offered after the below code throws an error:"
219     { $code
220         ": restart-test ( -- )"
221         "    \"Oops!\" { { \"One\" 1 } { \"Two\" 2 } } throw-restarts"
222         "    \"You restarted: \" write . ;"
223         "restart-test"
224     }
225 } ;
226
227 HELP: rethrow-restarts
228 { $values { "error" object } { "restarts" { $sequence { { $snippet "{ string object }" } " pairs" } } } { "restart" object } }
229 { $description "Throws a restartable error using " { $link rethrow } ". Otherwise, this word is identical to " { $link throw-restarts } "." } ;
230
231 { throw rethrow throw-restarts rethrow-restarts throw-continue } related-words
232
233 HELP: throw-continue
234 { $values { "error" object } }
235 { $description "Throws a resumable error. If the user elects to continue execution, this word returns normally." } ;
236
237 HELP: compute-restarts
238 { $values { "error" object } { "seq" sequence } }
239 { $description "Outputs a sequence of triples, where each triple consists of a human-readable string, an object, and a continuation. Resuming a continuation with the corresponding object restarts execution immediately after the corresponding call to " { $link condition } "."
240 $nl
241 "This word recursively travels up the delegation chain to collate restarts from nested and wrapped conditions." } ;
242
243 HELP: save-error
244 { $values { "error" "an error" } }
245 { $description "Called by the error handler to set the " { $link error } " and " { $link restarts } " global variables after an error was thrown." }
246 $low-level-note ;
247
248 HELP: with-datastack
249 { $values { "stack" sequence } { "quot" quotation } { "new-stack" sequence } }
250 { $description "Executes the quotation with the given data stack contents, and outputs the new data stack after the word returns. The input sequence is not modified; a new sequence is produced. Does not affect the data stack in surrounding code, other than consuming the two inputs and pushing the output." }
251 { $examples
252     { $example "USING: continuations math prettyprint ;" "{ 3 7 } [ + ] with-datastack ." "{ 10 }" }
253 } ;
254
255 HELP: attempt-all
256 { $values
257      { "seq" sequence } { "quot" quotation }
258      { "obj" object } }
259 { $description "Applies the quotation to elements in a sequence and returns the value from the first quotation that does not throw an error. If all quotations throw an error, returns the last error thrown." }
260 { $examples "The first two numbers throw, the last one doesn't:"
261     { $example
262     "USING: prettyprint continuations kernel math ;"
263     "{ 1 3 6 } [ dup odd? [ \"Odd\" throw ] when ] attempt-all ."
264     "6" }
265     "All quotations throw, the last exception is rethrown:"
266     { $example
267     "USING: prettyprint continuations kernel math ;"
268     "[ { 1 3 5 } [ dup odd? [ throw ] when ] attempt-all ] [ ] recover ."
269     "5"
270     }
271 } ;
272
273 HELP: return
274 { $description "Returns early from a quotation by reifying the continuation captured by " { $link with-return } " ; execution is resumed starting immediately after " { $link with-return } "." } ;
275
276 HELP: with-return
277 { $values
278      { "quot" quotation } }
279 { $description "Captures a continuation that can be reified by calling the " { $link return } " word. If so, it will resume execution immediately after the " { $link with-return } " word. If " { $link return } " is not called, then execution proceeds as if this word were simply " { $link call } "." }
280 { $examples
281     "Only \"Hi\" will print:"
282     { $example
283     "USING: prettyprint continuations io ;"
284     "[ \"Hi\" print return \"Bye\" print ] with-return"
285     "Hi"
286 } } ;
287
288 { return with-return } related-words
289
290 HELP: restart
291 { $values { "restart" restart } }
292 { $description "Invokes a restart." }
293 { $class-description "The class of restarts." } ;