diff options
| author | Stefan Monnier | 2024-01-04 16:28:39 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2024-01-04 16:39:48 -0500 |
| commit | ae75333ca78f5c45e53e7e5d25f4e04a4d69ad8f (patch) | |
| tree | 95bc5483e0fb5a979118ec85821c543582dc9e44 | |
| parent | 391c208aecc44fd82c599696d47a18782f2f36da (diff) | |
| download | emacs-ae75333ca78f5c45e53e7e5d25f4e04a4d69ad8f.tar.gz emacs-ae75333ca78f5c45e53e7e5d25f4e04a4d69ad8f.zip | |
Improve `handler-bind` doc
* doc/lispref/control.texi (Handling Errors) <handler-bind>: Expand.
* doc/lispref/variables.texi (Variable Scoping): Mention static scoping.
| -rw-r--r-- | doc/lispref/control.texi | 102 | ||||
| -rw-r--r-- | doc/lispref/variables.texi | 4 |
2 files changed, 93 insertions, 13 deletions
diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi index 6cc25dcdaee..3c9f26262c1 100644 --- a/doc/lispref/control.texi +++ b/doc/lispref/control.texi | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | @c -*- mode: texinfo; coding: utf-8 -*- | 1 | @c -*- mode: texinfo; coding: utf-8 -*- |
| 2 | @c This is part of the GNU Emacs Lisp Reference Manual. | 2 | @c This is part of the GNU Emacs Lisp Reference Manual. |
| 3 | @c Copyright (C) 1990--1995, 1998--1999, 2001--2024 Free Software | 3 | @c Copyright (C) 1990--2024 Free Software |
| 4 | @c Foundation, Inc. | 4 | @c Foundation, Inc. |
| 5 | @c See the file elisp.texi for copying conditions. | 5 | @c See the file elisp.texi for copying conditions. |
| 6 | @node Control Structures | 6 | @node Control Structures |
| @@ -2311,24 +2311,102 @@ form. In this case, the @code{handler-bind} has no effect. | |||
| 2311 | @code{(@var{conditions} @var{handler})} where @var{conditions} is an | 2311 | @code{(@var{conditions} @var{handler})} where @var{conditions} is an |
| 2312 | error condition name to be handled, or a list of condition names, and | 2312 | error condition name to be handled, or a list of condition names, and |
| 2313 | @var{handler} should be a form whose evaluation should return a function. | 2313 | @var{handler} should be a form whose evaluation should return a function. |
| 2314 | As with @code{condition-case}, condition names are symbols. | ||
| 2314 | 2315 | ||
| 2315 | Before running @var{body}, @code{handler-bind} evaluates all the | 2316 | Before running @var{body}, @code{handler-bind} evaluates all the |
| 2316 | @var{handler} forms and installs those handlers to be active during | 2317 | @var{handler} forms and installs those handlers to be active during |
| 2317 | the evaluation of @var{body}. These handlers are searched together | 2318 | the evaluation of @var{body}. When an error is signaled, |
| 2318 | with those installed by @code{condition-case}. When the innermost | 2319 | Emacs searches all the active @code{condition-case} and |
| 2320 | @code{handler-bind} forms for a handler that | ||
| 2321 | specifies one or more of these condition names. When the innermost | ||
| 2319 | matching handler is one installed by @code{handler-bind}, the | 2322 | matching handler is one installed by @code{handler-bind}, the |
| 2320 | @var{handler} function is called with a single argument holding the | 2323 | @var{handler} function is called with a single argument holding the |
| 2321 | error description. | 2324 | error description. |
| 2322 | 2325 | ||
| 2323 | @var{handler} is called in the dynamic context where the error | 2326 | Contrary to what happens with @code{condition-case}, @var{handler} is |
| 2324 | happened, without first unwinding the stack, meaning that all the | 2327 | called in the dynamic context where the error happened. This means it |
| 2325 | dynamic bindings are still in effect, except that all the error | 2328 | is executed unbinding any variable bindings or running any cleanups of |
| 2326 | handlers between the code that signaled the error and the | 2329 | @code{unwind-protect}, so that all those dynamic bindings are still in |
| 2327 | @code{handler-bind} are temporarily suspended. Like any normal | 2330 | effect. There is one exception: while running the @var{handler} |
| 2328 | function, @var{handler} can exit non-locally, typically via | 2331 | function, all the error handlers between the code that signaled the |
| 2329 | @code{throw}, or it can return normally. If @var{handler} returns | 2332 | error and the @code{handler-bind} are temporarily suspended, meaning |
| 2330 | normally, it means the handler @emph{declined} to handle the error and | 2333 | that when an error is signaled, Emacs will only search the active |
| 2331 | the search for an error handler is continued where it left off. | 2334 | @code{condition-case} and @code{handler-bind} forms that are inside |
| 2335 | the @var{handler} function or outside of the current | ||
| 2336 | @code{handler-bind}. Note also that lexical variables are not | ||
| 2337 | affected, since they do not have dynamic extent. | ||
| 2338 | |||
| 2339 | Like any normal function, @var{handler} can exit non-locally, | ||
| 2340 | typically via @code{throw}, or it can return normally. | ||
| 2341 | If @var{handler} returns normally, it means the handler | ||
| 2342 | @emph{declined} to handle the error and the search for an error | ||
| 2343 | handler is continued where it left off. | ||
| 2344 | |||
| 2345 | For example, if we wanted to keep a log of all the errors that occur | ||
| 2346 | during the execution of a particular piece of code together with the | ||
| 2347 | buffer that's current when the error is signaled, but without | ||
| 2348 | otherwise affecting the behavior of that code, we can do it with: | ||
| 2349 | |||
| 2350 | @example | ||
| 2351 | @group | ||
| 2352 | (handler-bind | ||
| 2353 | ((error | ||
| 2354 | (lambda (err) | ||
| 2355 | (push (cons err (current-buffer)) my-log-of-errors)))) | ||
| 2356 | @var{body-forms}@dots{}) | ||
| 2357 | @end group | ||
| 2358 | @end example | ||
| 2359 | |||
| 2360 | This will log only those errors that are not caught internally to | ||
| 2361 | @var{body-forms}@dots{}, in other words errors that ``escape'' from | ||
| 2362 | @var{body-forms}@dots{}, and it will not prevent those errors from | ||
| 2363 | being passed on to surrounding @code{condition-case} handlers (or | ||
| 2364 | @code{handler-bind} handlers for that matter) since the above handler | ||
| 2365 | returns normally. | ||
| 2366 | |||
| 2367 | We can also use @code{handler-bind} to replace an error with another, | ||
| 2368 | as in the code below which turns all errors of type @code{user-error} | ||
| 2369 | that occur during the execution of @var{body-forms}@dots{} into plain | ||
| 2370 | @code{error}: | ||
| 2371 | |||
| 2372 | @example | ||
| 2373 | @group | ||
| 2374 | (handler-bind | ||
| 2375 | ((user-error | ||
| 2376 | (lambda (err) | ||
| 2377 | (signal 'error (cdr err))))) | ||
| 2378 | @var{body-forms}@dots{}) | ||
| 2379 | @end group | ||
| 2380 | @end example | ||
| 2381 | |||
| 2382 | We can get almost the same result with @code{condition-case}: | ||
| 2383 | |||
| 2384 | @example | ||
| 2385 | @group | ||
| 2386 | (condition-case err | ||
| 2387 | (progn @var{body-forms}@dots{}) | ||
| 2388 | (user-error (signal 'error (cdr err)))) | ||
| 2389 | @end group | ||
| 2390 | @end example | ||
| 2391 | |||
| 2392 | @noindent | ||
| 2393 | but with the difference that when we (re)signal the new error in | ||
| 2394 | @code{handler-bind} the dynamic environment from the original error is | ||
| 2395 | still active, which means for example that if we enter the | ||
| 2396 | debugger at this point, it will show us a complete backtrace including | ||
| 2397 | the point where we signaled the original error: | ||
| 2398 | |||
| 2399 | @example | ||
| 2400 | @group | ||
| 2401 | Debugger entered--Lisp error: (error "Oops") | ||
| 2402 | signal(error ("Oops")) | ||
| 2403 | (closure (t) (err) (signal 'error (cdr err)))((user-error "Oops")) | ||
| 2404 | user-error("Oops") | ||
| 2405 | @dots{} | ||
| 2406 | eval((handler-bind ((user-error (lambda (err) @dots{} | ||
| 2407 | @end group | ||
| 2408 | @end example | ||
| 2409 | |||
| 2332 | @end defmac | 2410 | @end defmac |
| 2333 | 2411 | ||
| 2334 | @node Error Symbols | 2412 | @node Error Symbols |
diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi index 705d3260063..4d61d461deb 100644 --- a/doc/lispref/variables.texi +++ b/doc/lispref/variables.texi | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | @c -*-texinfo-*- | 1 | @c -*-texinfo-*- |
| 2 | @c This is part of the GNU Emacs Lisp Reference Manual. | 2 | @c This is part of the GNU Emacs Lisp Reference Manual. |
| 3 | @c Copyright (C) 1990--1995, 1998--2024 Free Software Foundation, Inc. | 3 | @c Copyright (C) 1990--2024 Free Software Foundation, Inc. |
| 4 | @c See the file elisp.texi for copying conditions. | 4 | @c See the file elisp.texi for copying conditions. |
| 5 | @node Variables | 5 | @node Variables |
| 6 | @chapter Variables | 6 | @chapter Variables |
| @@ -978,6 +978,7 @@ program is executing, the binding exists. | |||
| 978 | 978 | ||
| 979 | @cindex lexical binding | 979 | @cindex lexical binding |
| 980 | @cindex lexical scope | 980 | @cindex lexical scope |
| 981 | @cindex static scope | ||
| 981 | @cindex indefinite extent | 982 | @cindex indefinite extent |
| 982 | For historical reasons, there are two dialects of Emacs Lisp, | 983 | For historical reasons, there are two dialects of Emacs Lisp, |
| 983 | selected via the @code{lexical-binding} buffer-local variable. | 984 | selected via the @code{lexical-binding} buffer-local variable. |
| @@ -989,6 +990,7 @@ binding can also be accessed from the Lisp debugger.}. It also has | |||
| 989 | @dfn{indefinite extent}, meaning that under some circumstances the | 990 | @dfn{indefinite extent}, meaning that under some circumstances the |
| 990 | binding can live on even after the binding construct has finished | 991 | binding can live on even after the binding construct has finished |
| 991 | executing, by means of objects called @dfn{closures}. | 992 | executing, by means of objects called @dfn{closures}. |
| 993 | Lexical scoping is also commonly called @dfn{static scoping}. | ||
| 992 | 994 | ||
| 993 | @cindex dynamic binding | 995 | @cindex dynamic binding |
| 994 | @cindex dynamic scope | 996 | @cindex dynamic scope |