unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#68075: 30.0.50; New special form `handler-bind`
@ 2023-12-28  6:33 Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-12-28  8:03 ` Eli Zaretskii
  0 siblings, 1 reply; 19+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-12-28  6:33 UTC (permalink / raw)
  To: 68075; +Cc: monnier

Package: Emacs
Version: 30.0.50


I have now pushed to `scratch/handler-bind` a set of patches I'd like to
commit to `master`.  They add the new special form `handler-bind`, which
provides a functionality a bit halfway between `condition-case` and
`signal-hook-function`.

Among other things, this allows us to fix bug#11218, bug#65267, and
bug#67196.  It also makes it possible to move code out of
`signal_or_quit`.

The complete log can be found below, but the oneliners are:

    New special form `handler-bind`
    (eval-expression): Fix bug#67196
    ert.el: Use `handler-bind` to record backtraces
    Fix ert-tests.el for the new `handler-bind` code
    Use handler-bind to repair bytecomp-tests
    emacs-module-tests.el (mod-test-non-local-exit-signal-test): Repair test
    startup.el: Use `handler-bind` to implement `--debug-init`
    Move batch backtrace code to `top_level_2`
    (macroexp--with-extended-form-stack): Use plain `let`
    eval.c: Add new var `lisp-eval-depth-reserve`
    (signal_or_quit): Preserve error object identity
    (backtrace-on-redisplay-error): Use `handler-bind`

As you can see, the first commit adds the new feature, and subsequent
ones basically make use of it in various different places.

Among those commits, I'll note the introduction of a new variable
`lisp-eval-depth-reserve`, which lets us control how much Emacs can grow
`max-lisp-eval-depth` to run the debugger.  This is not indispensable,
but seemed like a good idea.  I also subtly changed the way errors
are built such that we can rely on the error object being `eq` to itself
as it moves up from the call to `signal` up to its `condition-case`
handler, which should make it possible to keep extra info about it
in an `eq` hashtable, for example.

Comments, objections?


        Stefan


commit a4efbe4c499623b33882a770c896ebfd31459ce9
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Date:   Mon Dec 25 22:32:17 2023 -0500

    New special form `handler-bind`
    
    AFAIK, this provides the same semantics as Common Lisp's `handler-bind`,
    modulo the differences about how error objects and conditions are
    represented.
    
    * lisp/subr.el (handler-bind): New macro.
    
    * src/eval.c (pop_handler): New function.
    (Fhandler_Bind_1): New function.
    (signal_or_quit): Handle new handlertypes `HANDLER` and `SKIP_CONDITIONS`.
    (find_handler_clause): Simplify.
    (syms_of_eval): Defsubr `Fhandler_bind_1`.
    
    * doc/lispref/control.texi (Handling Errors): Add `handler-bind`.
    
    * test/src/eval-tests.el (eval-tests--handler-bind): New test.
    
    * lisp/emacs-lisp/lisp-mode.el (lisp-font-lock-keywords):
    Move 'handler-bind' from CL-only to generic Lisp.
    (handler-bind): Remove indentation setting, it now lives in the macro
    definition.

commit 19f1d2a9f5111a2f06003f45f3af2a39c7029047
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Date:   Mon Dec 18 23:47:56 2023 -0500

    (eval-expression): Fix bug#67196
    
    * lisp/simple.el (eval-expression--debug): New function.
    (eval-expression): Use it together with `handler-bind` instead of
    let-binding `debug-on-error`.

commit ae21819496a7f003c4d4e185204533660197daaa
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Date:   Mon Dec 18 23:57:45 2023 -0500

    ert.el: Use `handler-bind` to record backtraces
    
    * lisp/emacs-lisp/ert.el (ert--should-signal-hook): Delete function.
    (ert--expand-should-1): Don't bind `signal-hook-function`.
    (ert--test-execution-info): Remove `next-debugger` slot.
    (ert--run-test-debugger): Adjust to new calling convention.
    Pass the `:backtrace-base` info to the debugger.
    (ert--run-test-internal): Use `handler-bind` rather than let-binding
    `debugger` and `debug-on-error`.
    
    * lisp/emacs-lisp/ert-x.el (ert-remote-temporary-file-directory): Don't
    use `defconst` if it's not meant to stay constant (e.g. we let-bind it
    in tramp-tests.el).

commit 89a298b3d2f86e75750617ef7e301372ea5aa46f
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Date:   Thu Dec 28 00:46:36 2023 -0500

    Fix ert-tests.el for the new `handler-bind` code
    
    Now that `ert.el` uses `handler-bind` instead of `debugger`, some
    details of the behavior have changed.  More specifically,
    three tests are now broken, but these basically tested the failure
    of ERT's machinery to record errors when ERT was run within
    a `condition-case`.
    AFAICT, these tests do not check for a behavior that we want,
    so rather than "fix" them, I disabled them.
    
    * test/lisp/emacs-lisp/ert-tests.el (ert-test-error-debug)
    (ert-test-fail-debug-with-condition-case)
    (ert-test-should-failure-debugging): Comment out.
    (ert-test-with-demoted-errors): It now passes.  Bug#11218 is fixed!

commit 1c1d2eb3e389bb5e397cd8e1568e4e3129067912
Author: Mattias Engdegård <mattiase@acm.org>
Date:   Wed Dec 27 11:32:49 2023 +0100

    Use handler-bind to repair bytecomp-tests
    
    * test/lisp/emacs-lisp/bytecomp-tests.el
    (bytecomp-tests--error-frame, bytecomp--byte-op-error-backtrace):
    Make test pass again and simplify, using handler-bind instead
    of the previous debugger hack.

commit dcf7508c947359866151171a840d99d939c35cdf
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Date:   Thu Dec 28 00:49:39 2023 -0500

    emacs-module-tests.el (mod-test-non-local-exit-signal-test): Repair test
    
    That test relied on `debugger` and `debug-on-signal` in a way that
    doesn't work with the new ERT code.
    
    * test/src/emacs-module-tests.el (mod-test-non-local-exit-signal-test):
    Use `handler-bind` rather than the debugger.

commit 917596160c1c831b3a41b320a0e357e5161cb4c8
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Date:   Tue Dec 19 19:46:47 2023 -0500

    startup.el: Use `handler-bind` to implement `--debug-init`
    
    This provides a more reliable fix for bug#65267 since we don't
    touch `debug-on-error` nor `debug-ignore-errors` any more.
    
    * lisp/startup.el (startup--debug): New function.
    (startup--load-user-init-file): Use it and `handler-bind` instead of
    let-binding `debug-on-error`.

commit 6a57b9151b149a445daecc211d8f58010e605768
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Date:   Wed Dec 20 23:31:39 2023 -0500

    Move batch backtrace code to `top_level_2`
    
    Move ad-hoc code meant to ease debugging of bootstrap (and batch mode)
    to `top_level_2` so it doesn't pollute `signal_or_quit`.
    
    * src/lisp.h (pop_handler, push_handler_bind): Declare.
    * src/keyboard.c (top_level_2): Setup an error handler to call
    `debug-early` when noninteractive.
    * src/eval.c (pop_handler): Not static any more.
    (signal_or_quit): Remove special case for noninteractive use.
    (push_handler_bind): New function, extracted from `Fhandler_bind_1`.
    (Fhandler_bind_1): Use it.
    (syms_of_eval): Declare `Qdebug_early__handler`.
    * lisp/emacs-lisp/debug-early.el (debug-early-backtrace): Weed out
    frames below `debug-early`.
    (debug-early--handler): New function.

commit 634bf61947606d1b8344ba090fdd0fc098fb5eb6
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Date:   Mon Dec 25 23:55:53 2023 -0500

    (macroexp--with-extended-form-stack): Use plain `let`
    
    `macroexp--with-extended-form-stack` used manual push/pop so that upon
    non-local exits the "deeper" value is kept, so the error handler gets
    to know what was the deeper value, so as to be able to compute more
    precise error locations.
    Replace this with a `handler-bind` which catches that "deeper" value
    more explicitly.
    
    * lisp/emacs-lisp/bytecomp.el (bytecomp--displaying-warnings):
    Use `handler-bind` to catch the value of `byte-compile-form-stack`
    at the time of the error.  Also consolidate the duplicated code.
    
    * lisp/emacs-lisp/macroexp.el (macroexp--with-extended-form-stack):
    Use a plain dynbound let-rebinding.

commit c89b234405f8fa6c52f83104a46a4a2c3121198f
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Date:   Tue Dec 26 23:56:09 2023 -0500

    eval.c: Add new var `lisp-eval-depth-reserve`
    
    Rather than blindly increase `max-lisp-eval-depth` when entering the
    debugger or running `signal-hook-function`, use this new "reserve"
    to keep track of how much we have grown the stack for "debugger"
    purposes so that for example recursive calls to `signal-hook-function`
    can't eat up the whole C stack.
    
    * src/eval.c (max_ensure_room): Rewrite.
    (restore_stack_limits): Move before `max_ensure_room`.  Rewrite.
    (call_debugger, signal_or_quit): Adjust calls accordingly.
    Also grow `max-lisp-eval-depth` for `hander-bind` handlers.
    (init_eval_once): Don't initialize `max_lisp_eval_depth` here.
    (syms_of_eval): Initialize it here instead.
    Add new var `lisp-eval-depth-reserve`.
    
    * doc/lispref/eval.texi (Eval): Add `lisp-eval-depth-reserve`.

commit b925152bffce30abbd48361af6858cd45b785d84
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Date:   Wed Dec 27 15:06:32 2023 -0500

    (signal_or_quit): Preserve error object identity
    
    Make sure we build the (ERROR-SYMBOL . ERROR-DATA) object only once
    when signaling an error, so that its `eq` identity can be used.
    It also gets us a tiny bit closer to having real "error objects"
    like in most other current programming languages.
    
    * src/eval.c (maybe_call_debugger): Change arglist to receive the error
    object instead of receiving the signal and the data separately.
    (signal_or_quit): Build the error object right at the beginning so it
    stays `eq` to itself.
    Rename the `keyboard_quit` arg to `continuable` so say what it does
    rather than what it's used for.
    (signal_quit_p): Change arg to be the error object rather than just the
    error-symbol.
    
    * src/keyboard.c (cmd_error_internal, menu_item_eval_property_1):
    Adjust calls to `signal_quit_p` accordingly.
    
    * test/src/eval-tests.el (eval-tests--error-id): New test.

commit 26b7078705ae5b9226c99e370740ab9a4063f20f
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Date:   Mon Dec 25 21:41:08 2023 -0500

    (backtrace-on-redisplay-error): Use `handler-bind`
    
    Reimplement `backtrace-on-redisplay-error` using `push_handler_bind`.
    This moves the code from `signal_or_quit` to `xdisp.c` and
    `debug-early.el`.
    
    * lisp/emacs-lisp/debug-early.el (debug-early-backtrace):
    Add `base` arg to strip "internal" frames.
    (debug--early): New function, extracted from `debug-early`.
    (debug-early, debug-early--handler): Use it.
    (debug-early--muted): New function, extracted (translated) from
    `signal_or_quit`; trim the buffer to a max of 10 backtraces.
    
    * src/xdisp.c (funcall_with_backtraces): New function.
    (dsafe_calln): Use it.
    (syms_of_xdisp): Defsym `Qdebug_early__muted`.
    
    * src/eval.c (redisplay_deep_handler): Delete var.
    (init_eval, internal_condition_case_n): Don't set it any more.
    (backtrace_yet): Delete var.
    (signal_or_quit): Remove special case for `backtrace_on_redisplay_error`.
    * src/keyboard.c (command_loop_1): Don't set `backtrace_yet` any more.
    * src/lisp.h (backtrace_yet): Don't declare.






^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2023-12-28  6:33 bug#68075: 30.0.50; New special form `handler-bind` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-12-28  8:03 ` Eli Zaretskii
  2023-12-28 18:12   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2023-12-28  8:03 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 68075

> Cc: monnier@iro.umontreal.ca
> Date: Thu, 28 Dec 2023 01:33:09 -0500
> From:  Stefan Monnier via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> 
> I have now pushed to `scratch/handler-bind` a set of patches I'd like to
> commit to `master`.  They add the new special form `handler-bind`, which
> provides a functionality a bit halfway between `condition-case` and
> `signal-hook-function`.
> 
> Among other things, this allows us to fix bug#11218, bug#65267, and
> bug#67196.  It also makes it possible to move code out of
> `signal_or_quit`.
> 
> The complete log can be found below, but the oneliners are:
> 
>     New special form `handler-bind`
>     (eval-expression): Fix bug#67196
>     ert.el: Use `handler-bind` to record backtraces
>     Fix ert-tests.el for the new `handler-bind` code
>     Use handler-bind to repair bytecomp-tests
>     emacs-module-tests.el (mod-test-non-local-exit-signal-test): Repair test
>     startup.el: Use `handler-bind` to implement `--debug-init`
>     Move batch backtrace code to `top_level_2`
>     (macroexp--with-extended-form-stack): Use plain `let`
>     eval.c: Add new var `lisp-eval-depth-reserve`
>     (signal_or_quit): Preserve error object identity
>     (backtrace-on-redisplay-error): Use `handler-bind`
> 
> As you can see, the first commit adds the new feature, and subsequent
> ones basically make use of it in various different places.
> 
> Among those commits, I'll note the introduction of a new variable
> `lisp-eval-depth-reserve`, which lets us control how much Emacs can grow
> `max-lisp-eval-depth` to run the debugger.  This is not indispensable,
> but seemed like a good idea.  I also subtly changed the way errors
> are built such that we can rely on the error object being `eq` to itself
> as it moves up from the call to `signal` up to its `condition-case`
> handler, which should make it possible to keep extra info about it
> in an `eq` hashtable, for example.
> 
> Comments, objections?

Assuming by the above you meant that the branch is from your POV ready
to land on master, please find some review comments below.

> diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
> index d4bd8c1..4107963 100644
> --- a/doc/lispref/control.texi
> +++ b/doc/lispref/control.texi
> @@ -2293,6 +2293,44 @@ Handling Errors
>  @code{condition-case-unless-debug} rather than @code{condition-case}.
>  @end defmac
>  
> +Occasionally, we want to catch some errors and record some information
> +about the conditions in which they occurred, such as the full
> +backtrace, or the current buffer.  This kinds of information is sadly
> +not available in the handlers of a @code{condition-case} because the
> +stack is unwound before running that handler, so the handler is run in
> +the dynamic context of the @code{condition-case} rather than that of
> +the place where the error was signaled.  For those circumstances, you
> +can use the following form:

The reference to "unwinding the stack before running handler" uses
terminology and assumes knowledge we don't generally expect from
readers of the ELisp manual.  This should be reworded to use the
terminology we use in other cases where we talk about "unwinding" and
error handlers.

> +@defmac handler-bind handlers body@dots{}
> +This special form runs @var{body} and if it executes without error,
> +the value it returns becomes the value of the @code{handler-bind}
> +form.  In this case, the @code{handler-bind} has no effect.
> +
> +@var{handlers} should be a list of elements of the form
> +@code{(@var{conditions} @var{handler})} where @var{conditions} is an
> +error condition name to be handled, or a list of condition names, and
> +@var{handler} should be a form whose evaluation should return a function.

CONDITIONs are symbols, aren't they?  The above says "condition
names", which could be interpreted as if they were strings instead.

> +Before running @var{body}, @code{handler-bind} evaluates all the
> +@var{handler} forms and installs those handlers to be active during
> +the evaluation of @var{body}.  These handlers are searched together
> +with those installed by @code{condition-case}.

This reference to condition-case might confuse: what does
condition-case have to do with handler-bind?  And if it is expected
that handler-bind is used inside condition-case, there should be some
text about it, and the examples we hopefully add should illustrate
that.

>                                                  When the innermost
> +matching handler is one installed by @code{handler-bind}, the
> +@var{handler} function is called with a single argument holding the
> +error description.

Is "error description" the same as "error name" above?  If so, let's
please use consistent wording to minimize the chances for confusion
and misunderstandings.

> +@var{handler} is called in the dynamic context where the error
> +happened, without first unwinding the stack, meaning that all the
> +dynamic bindings are still in effect,

Should we tell something about the effects of lexical-binding on those
"dynamic bindings"?

>                                       except that all the error
> +handlers between the code that signaled the error and the
> +@code{handler-bind} are temporarily suspended.

Not sure I understand what it means for those handlers to be
"suspended".  can the text say more about that?

>                                                  Like any normal
> +function, @var{handler} can exit non-locally, typically via
> +@code{throw}, or it can return normally.  If @var{handler} returns
> +normally, it means the handler @emph{declined} to handle the error and
> +the search for an error handler is continued where it left off.
> +@end defmac

I think we should have a couple of examples here, to show the utility
of handler-bind and how it is different from condition-case.

> +@defopt lisp-eval-depth-reserve
> +In order to be able to debug infinite recursion errors, Entry to the
                                                         ^^^
Typo.

> +Lisp debugger increases temporarily the value of
> +@code{max-lisp-eval-depth}, if there is little room left, to make sure
> +the debugger itself has room to execute.  The same happens when
> +running the handler of a @code{handler-bind}.

Please add here a cross-reference to where handler-bind is documented.

> +The variable @code{lisp-eval-depth-reserve} bounds the extra depth
> +that Emacs can add to @code{max-lisp-eval-depth} for those
> +exceptional circumstances.
> +@end defopt

I think this should document the default value.

> ++++
> +** New special form 'handler-bind'.
> +Provides a functionality similar to `condition-case` except it runs the
> +handler code without unwinding the stack, such that we can record the
> +backtrace and other dynamic state at the point of the error.

Please add here a link to the node in the ELisp manual where
handler-bind is described.

> -(defmacro displaying-byte-compile-warnings (&rest body)
> +(defmacro displaying-byte-compile-warnings (&rest body) ;FIXME: Namespace!
                                                           ^^^^^^^^^^^^^^^^^^
What about this FIXME?

> +(defmacro handler-bind (handlers &rest body)
> +  "Setup error HANDLERS around execution of BODY.
> +HANDLERS is a list of (CONDITIONS HANDLER) where
> +CONDITIONS should be a list of condition names (symbols) or
> +a single condition name and HANDLER is a form whose evaluation
                          ^
A comma is missing there.

> +returns a function.
> +When an error is signaled during execution of BODY, if that
> +error matches CONDITIONS, then the associated HANDLER
> +function is called with the error as argument.
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
"Error" or "condition name"?  If "error", then what does "error
matches CONDITIONS" mean in practice?

> +HANDLERs can either transfer the control via a non-local exit,
> +or return normally.  If they return normally the search for an
                        ^^^^^^^^^^^^^^
I'd suggest "If a handler returns" instead.  There's just one
HANDLER involved here, right?

> +error handler continues from where it left off."

This "from where it left off" sounds confusing: what does it mean?
IOW, how is it different from saying

  If a HANDLER returns normally, other CONDITIONS are searched for a
  match, and, if found, their HANDLERs are called.

Btw, this begs the question: what happens if none of the CONDITIONS
match?  In particular, what happens if a HANDLER is called, returns
normally, and none of the other CONDITIONS match?

> +  ;; FIXME: Completion support as in `condition-case'?
        ^^^^^
What about this FIXME?

> @@ -317,6 +312,7 @@ call_debugger (Lisp_Object arg)
>    /* Interrupting redisplay and resuming it later is not safe under
>       all circumstances.  So, when the debugger returns, abort the
>       interrupted redisplay by going back to the top-level.  */
> +  /* FIXME: Move this to the redisplay code?  */
        ^^^^^
And this one?

> +DEFUN ("handler-bind-1", Fhandler_bind_1, Shandler_bind_1, 1, MANY, 0,
> +       doc: /* Setup error handlers around execution of BODYFUN.
> +BODYFUN be a function and it is called with no arguments.
> +CONDITIONS should be a list of condition names (symbols).
> +When an error is signaled during executon of BODYFUN, if that
> +error matches one of CONDITIONS, then the associated HANDLER is
> +called with the error as argument.
> +HANDLER should either transfer the control via a non-local exit,
> +or return normally.
> +If it returns normally, the search for an error handler continues
> +from where it left off.

"Where it left off" strikes again...

> +      specpdl_ref count = SPECPDL_INDEX ();
> +      max_ensure_room (20);
> +      /* FIXME: 'handler-bind' makes `signal-hook-function' obsolete?  */
> +      /* FIXME: Here we still "split" the error object
> +         into its error-symbol and its error-data?  */
>        call2 (Vsignal_hook_function, error_symbol, data);
> +      unbind_to (count, Qnil);

FIXMEs again.

>  top_level_2 (void)
>  {
> -  return Feval (Vtop_level, Qnil);
> +  /* If we're in batch mode, print a backtrace unconditionally when
> +     encountering an error, to help with debugging.  */
> +  bool setup_handler = noninteractive;
> +  if (setup_handler)
> +    /* FIXME: Should we (re)use `list_of_error` from `xdisp.c`? */
> +    push_handler_bind (list1 (Qerror), Qdebug_early__handler, 0);

And again.

> +;; (ert-deftest ert-test-fail-debug-with-condition-case ()
> +;;   (let ((test (make-ert-test :body (lambda () (ert-fail "failure message")))))
> +;;     (condition-case condition
> +;;         (progn
> +;;           (let ((ert-debug-on-error t))
> +;;             (ert-run-test test))
> +;;           (cl-assert nil))
> +;;       ((error)
> +;;        (cl-assert (equal condition '(ert-test-failed "failure message")) t)))))

What about this and other places where some code was commented-out,
but not removed?  Those seem to be tests that you disable - why?  Are
they no longer pertinent, or do they fail for some reason that should
be fixed?

Last, but not least: do all the tests in the test suite pass after
these changes, both with and without native-compilation?

Thanks.





^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2023-12-28  8:03 ` Eli Zaretskii
@ 2023-12-28 18:12   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-12-28 18:14     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
                       ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-12-28 18:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 68075

>> Comments, objections?
>
> Assuming by the above you meant that the branch is from your POV ready
> to land on master,
> please find some review comments below.

That's right (tho I did expect that the doc needed some improvement :-)

> The reference to "unwinding the stack before running handler" uses
> terminology and assumes knowledge we don't generally expect from
> readers of the ELisp manual.  This should be reworded to use the
> terminology we use in other cases where we talk about "unwinding" and
> error handlers.

See patch below for my attempt to clarify.

>> +@var{handlers} should be a list of elements of the form
>> +@code{(@var{conditions} @var{handler})} where @var{conditions} is an
>> +error condition name to be handled, or a list of condition names, and
>> +@var{handler} should be a form whose evaluation should return a function.
>
> CONDITIONs are symbols, aren't they?  The above says "condition
> names", which could be interpreted as if they were strings instead.

I took this nomenclature from `condition-case` where we say:

    [...]
    Here @var{conditions} is an error condition name to be handled, or
    a list of condition names (which can include @code{debug} to allow
    the debugger to run before the handler).

I added a mention that these names are symbols.

>> +Before running @var{body}, @code{handler-bind} evaluates all the
>> +@var{handler} forms and installs those handlers to be active during
>> +the evaluation of @var{body}.  These handlers are searched together
>> +with those installed by @code{condition-case}.
>
> This reference to condition-case might confuse: what does
> condition-case have to do with handler-bind?

I'm trying to explain that when looking for a handler, we look both for
condition-case handler and handler-bind handlers and we use whichever is
"closest", i.e. more deeply nested.  So just like a local
`condition-case` overrides temporarily an outer one, the same holds not
only among `handler-bind`s but also between `condition-case` and
`handler-bind` as well.

See the patch for my attempt to clarify.

>>                                                  When the innermost
>> +matching handler is one installed by @code{handler-bind}, the
>> +@var{handler} function is called with a single argument holding the
>> +error description.
>
> Is "error description" the same as "error name" above?

No, it's I like to call the error object:

    @cindex error description
    The argument @var{var} is a variable.  @code{condition-case} does not
    bind this variable when executing the @var{protected-form}, only when it
    handles an error.  At that time, it binds @var{var} locally to an
    @dfn{error description}, which is a list giving the particulars of the
    error.  The error description has the form @code{(@var{error-symbol}
    . @var{data})}.  The handler can refer to this list to decide what to
    do.  For example, if the error is for failure opening a file, the file
    name is the second element of @var{data}---the third element of the
    error description.

> If so, let's please use consistent wording to minimize the chances for
> confusion and misunderstandings.

I wasn't familiar with the term "error description" either, but that's
apparently what we use in the Texinfo doc, so I used it specifically to
try and "use consistent wording" :-)

>> +@var{handler} is called in the dynamic context where the error
>> +happened, without first unwinding the stack, meaning that all the
>> +dynamic bindings are still in effect,
>
> Should we tell something about the effects of lexical-binding on those
> "dynamic bindings"?

It's not related to `handler-bind` in any case, so if
we want to say something about it, we should do it elsewhere (and
I think we already do when we discuss lexical binding).

>>                                       except that all the error
>> +handlers between the code that signaled the error and the
>> +@code{handler-bind} are temporarily suspended.
> Not sure I understand what it means for those handlers to be
> "suspended".  can the text say more about that?

Indeed, it's a delicate part of he semantics (the one that introduces
the need for the SKIP_CONDITIONS thingy in the C code).
Let me know how you like the new text below.

> I think we should have a couple of examples here, to show the utility
> of handler-bind and how it is different from condition-case.

I added two examples.

>> +@defopt lisp-eval-depth-reserve
>> +In order to be able to debug infinite recursion errors, Entry to the
>                                                          ^^^
> Typo.

Hmm... yes that's not right, thanks.

>> +The variable @code{lisp-eval-depth-reserve} bounds the extra depth
>> +that Emacs can add to @code{max-lisp-eval-depth} for those
>> +exceptional circumstances.
>> +@end defopt
> I think this should document the default value.

OK.

>> ++++
>> +** New special form 'handler-bind'.
>> +Provides a functionality similar to `condition-case` except it runs the
>> +handler code without unwinding the stack, such that we can record the
>> +backtrace and other dynamic state at the point of the error.
>
> Please add here a link to the node in the ELisp manual where
> handler-bind is described.

OK.

>> -(defmacro displaying-byte-compile-warnings (&rest body)
>> +(defmacro displaying-byte-compile-warnings (&rest body) ;FIXME: Namespace!
>                                                            ^^^^^^^^^^^^^^^^^^
> What about this FIXME?

Just a namespace uncleanliness I noticed when working on this code.

>> +(defmacro handler-bind (handlers &rest body)
>> +  "Setup error HANDLERS around execution of BODY.
>> +HANDLERS is a list of (CONDITIONS HANDLER) where
>> +CONDITIONS should be a list of condition names (symbols) or
>> +a single condition name and HANDLER is a form whose evaluation
>                           ^
> A comma is missing there.

Thanks.

>> +returns a function.
>> +When an error is signaled during execution of BODY, if that
>> +error matches CONDITIONS, then the associated HANDLER
>> +function is called with the error as argument.
>                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
> "Error" or "condition name"?

The actual error object (aka "error description").

> If "error", then what does "error matches CONDITIONS" mean
> in practice?

It means that the "type" or "error name" of the error if a "subtype" of
one of CONDITIONS.

Given that we represent errors as (ERROR-NAME . ERROR-DATA) rather than
as objects, the "type" of an error is just the ERROR-NAME symbol.
And the "subtyping" relation is defined by the `parent` arg to
`define-error`.

This is exactly the same as for `condition-case`, of course.

>> +HANDLERs can either transfer the control via a non-local exit,
>> +or return normally.  If they return normally the search for an
>                         ^^^^^^^^^^^^^^
> I'd suggest "If a handler returns" instead.  There's just one
> HANDLER involved here, right?

Thanks, yes.

>> +error handler continues from where it left off."
>
> This "from where it left off" sounds confusing: what does it mean?
> IOW, how is it different from saying
>
>   If a HANDLER returns normally, other CONDITIONS are searched for a
>   match, and, if found, their HANDLERs are called.
>
> Btw, this begs the question: what happens if none of the CONDITIONS
> match?  In particular, what happens if a HANDLER is called, returns
> normally, and none of the other CONDITIONS match?

Same as for `condition-case`, we keep searching in surrounding handlers.
Not sure how to say it more clearly without becoming too verbose for
a docstring.  That's what the Texinfo doc is for, no?

>> +  ;; FIXME: Completion support as in `condition-case'?
>        ^^^^^
> What about this FIXME?

Haven't implemented that yet.
`handler-bind` is not going to be used nearly as often as
`condition-case`, but I don't think it's very high priority to implement
this feature.
[ A more important completion feature in this area would be to complete
  the name of existing generic functions after `cl-defmethod` :-)  ]

>> @@ -317,6 +312,7 @@ call_debugger (Lisp_Object arg)
>>    /* Interrupting redisplay and resuming it later is not safe under
>>       all circumstances.  So, when the debugger returns, abort the
>>       interrupted redisplay by going back to the top-level.  */
>> +  /* FIXME: Move this to the redisplay code?  */
>         ^^^^^
> And this one?

That's the "redisplay_counter" patch we discussed elsewhere.  I have it
in the `scratch/handler-bind-2` branch, but it's not really related to
`handler-bind`.

>> +DEFUN ("handler-bind-1", Fhandler_bind_1, Shandler_bind_1, 1, MANY, 0,
>> +       doc: /* Setup error handlers around execution of BODYFUN.
>> +BODYFUN be a function and it is called with no arguments.
>> +CONDITIONS should be a list of condition names (symbols).
>> +When an error is signaled during executon of BODYFUN, if that
>> +error matches one of CONDITIONS, then the associated HANDLER is
>> +called with the error as argument.
>> +HANDLER should either transfer the control via a non-local exit,
>> +or return normally.
>> +If it returns normally, the search for an error handler continues
>> +from where it left off.
> "Where it left off" strikes again...

Of course :-)

>> +      specpdl_ref count = SPECPDL_INDEX ();
>> +      max_ensure_room (20);
>> +      /* FIXME: 'handler-bind' makes `signal-hook-function' obsolete?  */
>> +      /* FIXME: Here we still "split" the error object
>> +         into its error-symbol and its error-data?  */
>>        call2 (Vsignal_hook_function, error_symbol, data);
>> +      unbind_to (count, Qnil);
>
> FIXMEs again.

Yup.  For the first, I'm not yet sure if it really makes
`signal-hook-function` obsolete (I have PoC patches on `handler-bind-2`
to remove existing uses, but I'm not sure these DTRT).
For the second, it's an API problem we can't really fix without breaking
backward compatibility.  If we're lucky, we can declare
`signal-hook-function` obsolete and those problems will disappear.

>>  top_level_2 (void)
>>  {
>> -  return Feval (Vtop_level, Qnil);
>> +  /* If we're in batch mode, print a backtrace unconditionally when
>> +     encountering an error, to help with debugging.  */
>> +  bool setup_handler = noninteractive;
>> +  if (setup_handler)
>> +    /* FIXME: Should we (re)use `list_of_error` from `xdisp.c`? */
>> +    push_handler_bind (list1 (Qerror), Qdebug_early__handler, 0);
>
> And again.

Here, I'm really asking reviewers whether they think we should use
`list_of_error` here (which would require making it non-static and
declaring it in `lisp.h` or somesuch).

>> +;; (ert-deftest ert-test-fail-debug-with-condition-case ()
>> +;;   (let ((test (make-ert-test :body (lambda () (ert-fail "failure message")))))
>> +;;     (condition-case condition
>> +;;         (progn
>> +;;           (let ((ert-debug-on-error t))
>> +;;             (ert-run-test test))
>> +;;           (cl-assert nil))
>> +;;       ((error)
>> +;;        (cl-assert (equal condition '(ert-test-failed "failure message")) t)))))
>
> What about this and other places where some code was commented-out,
> but not removed?  Those seem to be tests that you disable - why?

The commit message explains it:

    Now that `ert.el` uses `handler-bind` instead of `debugger`, some
    details of the behavior have changed.  More specifically,
    three tests are now broken, but these basically tested the failure
    of ERT's machinery to record errors when ERT was run within
    a `condition-case`.
    AFAICT, these tests do not check for a behavior that we want,
    so rather than "fix" them, I disabled them.

Maybe I should delete them rather than comment them out?

I guess I could also keep them commented out but with the above commit
message turned into a comment, but in that case I have to move those
3 tests so they can be together next to the new comment.

Either way works for me.

> Last, but not least: do all the tests in the test suite pass after
> these changes, both with and without native-compilation?

Yup.


        Stefan






^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2023-12-28 18:12   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-12-28 18:14     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-12-30  7:50       ` Eli Zaretskii
  2023-12-28 18:25     ` Ihor Radchenko
  2023-12-30  7:52     ` Eli Zaretskii
  2 siblings, 1 reply; 19+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-12-28 18:14 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 68075

> See patch below for my attempt to clarify.

Sigh!

Here it is,


        Stefan


diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
index 4107963eed5..e63660206d0 100644
--- a/doc/lispref/control.texi
+++ b/doc/lispref/control.texi
@@ -2311,24 +2311,100 @@ Handling Errors
 @code{(@var{conditions} @var{handler})} where @var{conditions} is an
 error condition name to be handled, or a list of condition names, and
 @var{handler} should be a form whose evaluation should return a function.
+As with @code{condition-case}, condition names are symbols.
 
 Before running @var{body}, @code{handler-bind} evaluates all the
 @var{handler} forms and installs those handlers to be active during
-the evaluation of @var{body}.  These handlers are searched together
-with those installed by @code{condition-case}.  When the innermost
+the evaluation of @var{body}.  When an error is signaled,
+Emacs searches all the active @code{condition-case} and
+@code{handler-bind} forms for a handler that
+specifies one or more of these condition names.  When the innermost
 matching handler is one installed by @code{handler-bind}, the
 @var{handler} function is called with a single argument holding the
 error description.
 
-@var{handler} is called in the dynamic context where the error
-happened, without first unwinding the stack, meaning that all the
-dynamic bindings are still in effect, except that all the error
-handlers between the code that signaled the error and the
-@code{handler-bind} are temporarily suspended.  Like any normal
-function, @var{handler} can exit non-locally, typically via
-@code{throw}, or it can return normally.  If @var{handler} returns
-normally, it means the handler @emph{declined} to handle the error and
-the search for an error handler is continued where it left off.
+Contrary to what happens with @code{condition-case}, @var{handler} is
+called in the dynamic context where the error happened, without
+unbinding any variable bindings or running any cleanups of
+@code{unwind-protect}, so that all those dynamic bindings are still in
+effect.  There is one exception: while running the @var{handler}
+function, all the error handlers between the code that signaled the
+error and the @code{handler-bind} are temporarily suspended, meaning
+that when an error is signaled, Emacs will only search the active
+@code{condition-case} and @code{handler-bind} forms that are inside
+the @var{handler} function or outside of the current
+@code{handler-bind}.
+
+Like any normal function, @var{handler} can exit non-locally,
+typically via @code{throw}, or it can return normally.
+If @var{handler} returns normally, it means the handler
+@emph{declined} to handle the error and the search for an error
+handler is continued where it left off.
+
+For example, if we wanted to keep a log of all the errors that occur
+during the execution of a particular piece of code together with the
+buffer that's current when the error is signaled, but without
+otherwise affecting the behavior of that code, we can do it with:
+
+@example
+@group
+(handler-bind
+    ((error
+      (lambda (err)
+        (push (cons err (current-buffer)) my-log-of-errors))))
+  @var{body-forms}@dots{})
+@end group
+@end example
+
+This will log only those errors that are not caught internally to
+@var{body-forms}@dots{}, in other words errors that ``escape'' from
+@var{body-forms}@dots{}, and it will not prevent those errors from
+being passed on to surrounding @code{condition-case} handlers (or
+@code{handler-bind} handlers for that matter) since the above handler
+returns normally.
+
+We can also use @code{handler-bind} to replace an error with another,
+as in the code below which turns all errors of type @code{user-error}
+that occur during the execution of @var{body-forms}@dots{} into plain
+@code{error}:
+
+@example
+@group
+(handler-bind
+    ((user-error
+      (lambda (err)
+        (signal 'error (cdr err)))))
+  @var{body-forms}@dots{})
+@end group
+@end example
+
+We can get almost the same result with @code{condition-case}:
+
+@example
+@group
+(condition-case err
+    (progn @var{body-forms}@dots{})
+  (user-error (signal 'error (cdr err))))
+@end group
+@end example
+
+But with the difference that when we (re)signal the new error in
+@code{handler-bind} the dynamic environment from the original error is
+still active, which means for example that if we were to enter the
+debugger at this point, it will show us a complete backtrace including
+the point where we signaled the original error:
+
+@example
+@group
+Debugger entered--Lisp error: (error "Oops")
+  signal(error ("Oops"))
+  (closure (t) (err) (signal 'error (cdr err)))((user-error "Oops"))
+  user-error("Oops")
+  @dots{}
+  eval((handler-bind ((user-error (lambda (err) @dots{}
+@end group
+@end example
+
 @end defmac
 
 @node Error Symbols
diff --git a/doc/lispref/eval.texi b/doc/lispref/eval.texi
index 45c892ad5a7..c3d980e1717 100644
--- a/doc/lispref/eval.texi
+++ b/doc/lispref/eval.texi
@@ -848,15 +848,17 @@ Eval
 @end defopt
 
 @defopt lisp-eval-depth-reserve
-In order to be able to debug infinite recursion errors, Entry to the
-Lisp debugger increases temporarily the value of
+In order to be able to debug infinite recursion errors, when invoking the
+Lisp debugger, Emacs increases temporarily the value of
 @code{max-lisp-eval-depth}, if there is little room left, to make sure
 the debugger itself has room to execute.  The same happens when
-running the handler of a @code{handler-bind}.
+running the handler of a @code{handler-bind}.  @xref{Handling Errors}.
 
 The variable @code{lisp-eval-depth-reserve} bounds the extra depth
 that Emacs can add to @code{max-lisp-eval-depth} for those
 exceptional circumstances.
+
+The default value of this variable is 200.
 @end defopt
 
 
diff --git a/etc/NEWS b/etc/NEWS
index 014c32b4d8e..e446f05190a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1371,6 +1371,7 @@ It puts a limit to the amount by which Emacs can temporarily increase
 Provides a functionality similar to `condition-case` except it runs the
 handler code without unwinding the stack, such that we can record the
 backtrace and other dynamic state at the point of the error.
+See the Info node "(elisp) Handling Errors".
 
 +++
 ** New 'pop-up-frames' action alist entry for 'display-buffer'.
diff --git a/lisp/subr.el b/lisp/subr.el
index 600b4d27f18..57e2473c2bb 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -7501,13 +7501,13 @@ handler-bind
   "Setup error HANDLERS around execution of BODY.
 HANDLERS is a list of (CONDITIONS HANDLER) where
 CONDITIONS should be a list of condition names (symbols) or
-a single condition name and HANDLER is a form whose evaluation
+a single condition name, and HANDLER is a form whose evaluation
 returns a function.
 When an error is signaled during execution of BODY, if that
 error matches CONDITIONS, then the associated HANDLER
-function is called with the error as argument.
+function is called with the error object as argument.
 HANDLERs can either transfer the control via a non-local exit,
-or return normally.  If they return normally the search for an
+or return normally.  If a handler returns normally, the search for an
 error handler continues from where it left off."
   ;; FIXME: Completion support as in `condition-case'?
   (declare (indent 1) (debug ((&rest (sexp form)) body)))






^ permalink raw reply related	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2023-12-28 18:12   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-12-28 18:14     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-12-28 18:25     ` Ihor Radchenko
  2023-12-28 22:04       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-12-30  7:52     ` Eli Zaretskii
  2 siblings, 1 reply; 19+ messages in thread
From: Ihor Radchenko @ 2023-12-28 18:25 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, 68075

Stefan Monnier via "Bug reports for GNU Emacs, the Swiss army knife of
text editors" <bug-gnu-emacs@gnu.org> writes:

> I'm trying to explain that when looking for a handler, we look both for
> condition-case handler and handler-bind handlers and we use whichever is
> "closest", i.e. more deeply nested.  So just like a local
> `condition-case` overrides temporarily an outer one, the same holds not
> only among `handler-bind`s but also between `condition-case` and
> `handler-bind` as well.

Then, it would also make sense to make `condition-case' and
`handler-bind' refer to each other from the docstrings.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2023-12-28 18:25     ` Ihor Radchenko
@ 2023-12-28 22:04       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 0 replies; 19+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-12-28 22:04 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Eli Zaretskii, 68075

>> I'm trying to explain that when looking for a handler, we look both for
>> condition-case handler and handler-bind handlers and we use whichever is
>> "closest", i.e. more deeply nested.  So just like a local
>> `condition-case` overrides temporarily an outer one, the same holds not
>> only among `handler-bind`s but also between `condition-case` and
>> `handler-bind` as well.
>
> Then, it would also make sense to make `condition-case' and
> `handler-bind' refer to each other from the docstrings.

BTW, `condition-case` can be implemented as a macro on top of
`handler-bind` and `catch`, e.g.

    (condition-case ERR FORM (error HANDLER))

can become something like:

    (let* ((tag (cons nil nil))
           (ERR (catch tag
                  (handler-bind ((error (lambda (err) (throw tag err))))
                    (cons 'noerror FORM)))))
      (if (eq 'noerror (car ERR))
          (cdr ERR)
        HANDLER))

:-)


-- Stefan






^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2023-12-28 18:14     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-12-30  7:50       ` Eli Zaretskii
  0 siblings, 0 replies; 19+ messages in thread
From: Eli Zaretskii @ 2023-12-30  7:50 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 68075

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: 68075@debbugs.gnu.org
> Date: Thu, 28 Dec 2023 13:14:25 -0500
> 
> +We can get almost the same result with @code{condition-case}:
> +
> +@example
> +@group
> +(condition-case err
> +    (progn @var{body-forms}@dots{})
> +  (user-error (signal 'error (cdr err))))
> +@end group
> +@end example
> +
> +But with the difference that when we (re)signal the new error in

You want to start the above line with a lower-case "but", and you want
a @noindent before it.





^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2023-12-28 18:12   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-12-28 18:14     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-12-28 18:25     ` Ihor Radchenko
@ 2023-12-30  7:52     ` Eli Zaretskii
  2023-12-31 19:07       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2023-12-30  7:52 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 68075

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: 68075@debbugs.gnu.org
> Date: Thu, 28 Dec 2023 13:12:12 -0500
> 
> >> +@var{handler} is called in the dynamic context where the error
> >> +happened, without first unwinding the stack, meaning that all the
> >> +dynamic bindings are still in effect,
> >
> > Should we tell something about the effects of lexical-binding on those
> > "dynamic bindings"?
> 
> It's not related to `handler-bind` in any case, so if
> we want to say something about it, we should do it elsewhere (and
> I think we already do when we discuss lexical binding).

Maybe I'm confused by your use of "dynamic context" and "dynamic
bindings" in that passage, which somehow hinted on dynamic vs lexical
binding.  If this is irrelevant, maybe try to reword the text so that
this potentially confusing terminology is not used?

Thanks.





^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2023-12-30  7:52     ` Eli Zaretskii
@ 2023-12-31 19:07       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-12-31 19:36         ` Eli Zaretskii
  0 siblings, 1 reply; 19+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-12-31 19:07 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 68075

>> >> +@var{handler} is called in the dynamic context where the error
>> >> +happened, without first unwinding the stack, meaning that all the
>> >> +dynamic bindings are still in effect,
>> >
>> > Should we tell something about the effects of lexical-binding on those
>> > "dynamic bindings"?
>> 
>> It's not related to `handler-bind` in any case, so if
>> we want to say something about it, we should do it elsewhere (and
>> I think we already do when we discuss lexical binding).
>
> Maybe I'm confused by your use of "dynamic context" and "dynamic
> bindings" in that passage, which somehow hinted on dynamic vs lexical
> binding.

Of course: "dynamic context" refers to things that include dynamically
bound variable (as well as the set of active catch tags, error handlers,
and unwind-protect forms), and does not include statically bound
variables.  `handler-bind` is different from `condition-case` in the way
it interacts with that dynamic context.  But for statically bound
variables, well, they obey the rules of static scoping so there's
nothing to influence here.

> If this is irrelevant, maybe try to reword the text so that
> this potentially confusing terminology is not used?

Could you give an example piece of code where this "confusing
terminology" makes you unsure how things would work?


        Stefan






^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2023-12-31 19:07       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-12-31 19:36         ` Eli Zaretskii
  2024-01-01 15:37           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2023-12-31 19:36 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 68075

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: 68075@debbugs.gnu.org
> Date: Sun, 31 Dec 2023 14:07:18 -0500
> 
> >> >> +@var{handler} is called in the dynamic context where the error
> >> >> +happened, without first unwinding the stack, meaning that all the
> >> >> +dynamic bindings are still in effect,
> >> >
> >> > Should we tell something about the effects of lexical-binding on those
> >> > "dynamic bindings"?
> >> 
> >> It's not related to `handler-bind` in any case, so if
> >> we want to say something about it, we should do it elsewhere (and
> >> I think we already do when we discuss lexical binding).
> >
> > Maybe I'm confused by your use of "dynamic context" and "dynamic
> > bindings" in that passage, which somehow hinted on dynamic vs lexical
> > binding.
> 
> Of course: "dynamic context" refers to things that include dynamically
> bound variable (as well as the set of active catch tags, error handlers,
> and unwind-protect forms), and does not include statically bound
> variables.  `handler-bind` is different from `condition-case` in the way
> it interacts with that dynamic context.  But for statically bound
> variables, well, they obey the rules of static scoping so there's
> nothing to influence here.
> 
> > If this is irrelevant, maybe try to reword the text so that
> > this potentially confusing terminology is not used?
> 
> Could you give an example piece of code where this "confusing
> terminology" makes you unsure how things would work?

That's the quoted part of your patch at the beginning of this message.
It uses the word "dynamic" twice and "dynamic bindings" once.





^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2023-12-31 19:36         ` Eli Zaretskii
@ 2024-01-01 15:37           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-01-01 16:06             ` Eli Zaretskii
  0 siblings, 1 reply; 19+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-01 15:37 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 68075

>> Could you give an example piece of code where this "confusing
>> terminology" makes you unsure how things would work?
> That's the quoted part of your patch at the beginning of this message.
> It uses the word "dynamic" twice and "dynamic bindings" once.

So, IIUC, reading that text makes you feel unsure, but you don't really
know what you're unsure of?  Not sure how to fix that.  Should I just
add a line that says that statically scoped variables are not affected?
It feels kinda of odd/redundant to say that since by definition they're
not "dynamic" (and also, any other behavior in this respect would be
*very* weird since the handlers are clearly function *values* and thus
could just as well be written/computed right *before* the
`handler-bind`).  More  importantly I get the impression that it will
still leave a lingering feeling that you're unsure about what other
things could be affected (and how) or about what it means to
be affected.

For this reason it would help if you could try and characterize more
precisely what you find confusing.


        Stefan






^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2024-01-01 15:37           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-01-01 16:06             ` Eli Zaretskii
  2024-01-01 16:55               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2024-01-01 16:06 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 68075

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: 68075@debbugs.gnu.org
> Date: Mon, 01 Jan 2024 10:37:01 -0500
> 
> >> Could you give an example piece of code where this "confusing
> >> terminology" makes you unsure how things would work?
> > That's the quoted part of your patch at the beginning of this message.
> > It uses the word "dynamic" twice and "dynamic bindings" once.
> 
> So, IIUC, reading that text makes you feel unsure, but you don't really
> know what you're unsure of?

Oh, but I do: the two references to "dynamic", including one to
"dynamic binding" seem to indicate quite unequivocally that "dynamic
binding" vs "lexical binding" could be involved.

I wonder why it is so hard to understand this difficulty, when the
words basically speak for themselves.

> For this reason it would help if you could try and characterize more
> precisely what you find confusing.

I don't have anything else to say except point once again to your
wording, which  I already did several times...





^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2024-01-01 16:06             ` Eli Zaretskii
@ 2024-01-01 16:55               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-01-01 17:35                 ` Eli Zaretskii
  0 siblings, 1 reply; 19+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-01 16:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 68075

>> So, IIUC, reading that text makes you feel unsure, but you don't really
>> know what you're unsure of?
>
> Oh, but I do: the two references to "dynamic", including one to
> "dynamic binding" seem to indicate quite unequivocally that "dynamic
> binding" vs "lexical binding" could be involved.

Yes, it is involved: statically scoped vars are not affected, while
dynamically scoped vars are affected, which is why the text says
"dynamic".

> I wonder why it is so hard to understand this difficulty, when the
> words basically speak for themselves.

I guess I don't understand how "the words basically speak for
themselves" leads to a difficulty.

>> For this reason it would help if you could try and characterize more
>> precisely what you find confusing.
> I don't have anything else to say except point once again to your
> wording, which I already did several times...

Sadly, I still fail to grasp what kind of change to the wording could
address the problem because I still don't really understand the problem.
Maybe you could try to rewrite that bit in a way that you find more
clear (or if there's still some part of the behavior over which you have
doubts, then I'd be happily to try and explain it further).


        Stefan






^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2024-01-01 16:55               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-01-01 17:35                 ` Eli Zaretskii
  2024-01-02  4:56                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2024-01-01 17:35 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 68075

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: 68075@debbugs.gnu.org
> Date: Mon, 01 Jan 2024 11:55:43 -0500
> 
> >> So, IIUC, reading that text makes you feel unsure, but you don't really
> >> know what you're unsure of?
> >
> > Oh, but I do: the two references to "dynamic", including one to
> > "dynamic binding" seem to indicate quite unequivocally that "dynamic
> > binding" vs "lexical binding" could be involved.
> 
> Yes, it is involved: statically scoped vars are not affected, while
> dynamically scoped vars are affected, which is why the text says
> "dynamic".

Ah, so lexical binding _is_ relevant to this, in the sense that
lexically-bound variables are _not_ affected!  Then please say that,
maybe in parentheses or as a footnote.

And please don't use "statically scoped", because we don't use this
terminology anywhere in the ELisp manual.  We always say "lexical
scoping".

> Sadly, I still fail to grasp what kind of change to the wording could
> address the problem because I still don't really understand the problem.
> Maybe you could try to rewrite that bit in a way that you find more
> clear (or if there's still some part of the behavior over which you have
> doubts, then I'd be happily to try and explain it further).

I hope now it is more clear.





^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2024-01-01 17:35                 ` Eli Zaretskii
@ 2024-01-02  4:56                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-01-04 23:57                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-01-05  0:50                     ` Stefan Kangas
  0 siblings, 2 replies; 19+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-02  4:56 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 68075

>> >> So, IIUC, reading that text makes you feel unsure, but you don't really
>> >> know what you're unsure of?
>> >
>> > Oh, but I do: the two references to "dynamic", including one to
>> > "dynamic binding" seem to indicate quite unequivocally that "dynamic
>> > binding" vs "lexical binding" could be involved.
>>
>> Yes, it is involved: statically scoped vars are not affected, while
>> dynamically scoped vars are affected, which is why the text says
>> "dynamic".
>
> Ah, so lexical binding _is_ relevant to this, in the sense that
> lexically-bound variables are _not_ affected!

Right, it's relevant to the extent that it's ... not relevant :-)

> Then please say that, maybe in parentheses or as a footnote.

OK.  [ Tho I feel it is kind of silly, since as soon as you consider
actual examples, it should become obvious that it has to be the case.  ]

> And please don't use "statically scoped",

I use it in email messages, because I consider it to be the better term,
from a technical point of view.  But indeed, I don't use it in the docs,
because it's too late to fix it there.

>> Sadly, I still fail to grasp what kind of change to the wording could
>> address the problem because I still don't really understand the problem.
>> Maybe you could try to rewrite that bit in a way that you find more
>> clear (or if there's still some part of the behavior over which you have
>> doubts, then I'd be happily to try and explain it further).
>
> I hope now it is more clear.

Kind of.  I still don't understand how/why it helps you, but at least you
say it does, which I guess is good enough.


        Stefan






^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2024-01-02  4:56                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-01-04 23:57                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-01-05  0:38                       ` Stefan Kangas
  2024-01-05  0:50                     ` Stefan Kangas
  1 sibling, 1 reply; 19+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-04 23:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 68075-done

Pushed to `master`, closing,


        Stefan






^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2024-01-04 23:57                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-01-05  0:38                       ` Stefan Kangas
  0 siblings, 0 replies; 19+ messages in thread
From: Stefan Kangas @ 2024-01-05  0:38 UTC (permalink / raw)
  To: Stefan Monnier, Eli Zaretskii; +Cc: 68075

Stefan Monnier via "Bug reports for GNU Emacs, the Swiss army knife of
text editors" <bug-gnu-emacs@gnu.org> writes:

> Pushed to `master`, closing,

Thanks!





^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2024-01-02  4:56                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-01-04 23:57                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-01-05  0:50                     ` Stefan Kangas
  2024-01-05  2:57                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 19+ messages in thread
From: Stefan Kangas @ 2024-01-05  0:50 UTC (permalink / raw)
  To: Stefan Monnier, Eli Zaretskii; +Cc: 68075

Stefan Monnier via "Bug reports for GNU Emacs, the Swiss army knife of
text editors" <bug-gnu-emacs@gnu.org> writes:

>> And please don't use "statically scoped",
>
> I use it in email messages, because I consider it to be the better term,
> from a technical point of view.  But indeed, I don't use it in the docs,
> because it's too late to fix it there.

I'm thumbing through my Dragon book for other reasons and they say
"static scope or lexical scope".  The index item for "lexical scope"
says "see static scope".

We already have an index entry for "dynamic scope" in the elisp manual.
Would it make sense to add an index item for "static scope" too?





^ permalink raw reply	[flat|nested] 19+ messages in thread

* bug#68075: 30.0.50; New special form `handler-bind`
  2024-01-05  0:50                     ` Stefan Kangas
@ 2024-01-05  2:57                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 0 replies; 19+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-05  2:57 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: Eli Zaretskii, 68075

> We already have an index entry for "dynamic scope" in the elisp manual.
> Would it make sense to add an index item for "static scope" too?

% grep 'static scope' **/*.texi
doc/lispref/variables.texi:@cindex static scope
%

🙂


        Stefan






^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2024-01-05  2:57 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-28  6:33 bug#68075: 30.0.50; New special form `handler-bind` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-12-28  8:03 ` Eli Zaretskii
2023-12-28 18:12   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-12-28 18:14     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-12-30  7:50       ` Eli Zaretskii
2023-12-28 18:25     ` Ihor Radchenko
2023-12-28 22:04       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-12-30  7:52     ` Eli Zaretskii
2023-12-31 19:07       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-12-31 19:36         ` Eli Zaretskii
2024-01-01 15:37           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-01 16:06             ` Eli Zaretskii
2024-01-01 16:55               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-01 17:35                 ` Eli Zaretskii
2024-01-02  4:56                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-04 23:57                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-05  0:38                       ` Stefan Kangas
2024-01-05  0:50                     ` Stefan Kangas
2024-01-05  2:57                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).