zsh-workers
 help / color / mirror / code / Atom feed
* [PATCH] Better ERR_EXIT and ERR_RETURN documentation
@ 2022-12-12 16:03 Philippe Altherr
  2022-12-12 16:21 ` Bart Schaefer
  0 siblings, 1 reply; 3+ messages in thread
From: Philippe Altherr @ 2022-12-12 16:03 UTC (permalink / raw)
  To: Zsh hackers list


[-- Attachment #1.1: Type: text/plain, Size: 3215 bytes --]

Here is a patch that updates the documentation of the ERR_EXIT and
ERR_RETURN options. The main improvement is to better explain when these
options are ignored.

As it may be a bit difficult to read it directly in the patch, I reproduced
below the updated documentation:

*ERR_EXIT*


> If a command has a non-zero exit status, execute the tt(ZERR)
> trap, if set, and exit.


> The option is ignored when executing the commands following tt(while),

tt(until), tt(if), or tt(elif), a pipeline beginning with tt(!), or
> any command other than the last in command list containing tt(&&) or
> tt(||).  Hence neither `tt(if foo; then true; fi)', nor `tt(foo &&
> true)' trigger exit when tt(foo) returns with a non-zero exit status.
> Note that if tt(foo) is a function, the option is also ignored during
> its whole execution.


> The option is also ignored when executing a complex command (tt(if),
> tt(for), tt(while), tt(until), tt(repeat), tt(case), tt(select),
> tt(always), or a list in braces) if its exit status comes from a
> command executed while the option is ignored. Hence, the tt(if)
> command in `tt(if true; then false && true; fi)' does not trigger
> exit.


> Finally, the option is also ignored while running initialization
> scripts and inside tt(DEBUG) traps.  In the latter case, the option is
> handled specially: it is unset on entry to the trap.  If the option
> tt(DEBUG_BEFORE_CMD) is set, as it is by default, and the option
> tt(ERR_EXIT) is found to have been set on exit, then the command for
> which the tt(DEBUG) trap is being executed is skipped.  The option is
> restored after the trap exits.


Exiting due to tt(ERR_EXIT) has certain interactions with asynchronous
> jobs noted in
> ifzman(the section JOBS in zmanref(zshmisc))\
> ifnzman(noderef(Jobs & Signals)).


> Note this behaviour is not disabled in interactive shells ---
> a non-zero status on the command line causes the shell to exit.


*ERR_RETURN*

If a command has a non-zero exit status, return immediately from the
> enclosing function.  Except for the exceptions described below, the
> logic is the same as that for tt(ERR_EXIT), except that an implicit
> tt(return) statement is executed instead of an tt(exit).  This will
> trigger an exit at the outermost level of a non-interactive script.
> At the top level of an interactive shell, it will trigger a return to
> the command prompt; in other words, the sequence of commands typed by
> the user may be thought of as a function for this purpose.


> Unlike for tt(ERR_EXIT), when a function is called while the option is
> being ignored, the option is NOT ignored during the execution of the
> function.  Hence, if tt(foo) in `tt(foo && true)' is a function, code
> inside it is considered separately: it may force a return from tt(foo)
> (assuming the option remains set within tt(foo)).


> Like for tt(ERR_EXIT), the option is ignored inside tt(DEBUG) traps
> but it's not unset on entry to the trap and setting or unsetting it
> inside the trap has no special effect.


> If tt(ERR_RETURN) and tt(ERR_EXIT) are both set, the latter takes
> precedence. Hence, exit rather than return is triggered when a command
> has a non-zero exit status.


Philippe

[-- Attachment #1.2: Type: text/html, Size: 5910 bytes --]

[-- Attachment #2: patch-errexit-documentation-update.txt --]
[-- Type: text/plain, Size: 4761 bytes --]

diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index e92969531..698943fa7 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -1723,22 +1723,30 @@ pindex(NOERREXIT)
 cindex(exit status, trapping)
 item(tt(ERR_EXIT) (tt(-e), ksh: tt(-e)))(
 If a command has a non-zero exit status, execute the tt(ZERR)
-trap, if set, and exit.  This is disabled while running initialization
-scripts.
-
-The behaviour is also disabled inside tt(DEBUG) traps.  In this
-case the option is handled specially: it is unset on entry to
-the trap.  If the option tt(DEBUG_BEFORE_CMD) is set,
-as it is by default, and the option tt(ERR_EXIT) is found to have been set
-on exit, then the command for which the tt(DEBUG) trap is being executed is
-skipped.  The option is restored after the trap exits.
-
-Non-zero status in a command list containing tt(&&) or tt(||) is ignored
-for commands not at the end of the list.  Hence
-
-example(false && true)
-
-does not trigger exit.
+trap, if set, and exit.
+
+The option is ignored when executing the commands following tt(while),
+tt(until), tt(if), or tt(elif), a pipeline beginning with tt(!), or
+any command other than the last in command list containing tt(&&) or
+tt(||).  Hence neither `tt(if foo; then true; fi)', nor `tt(foo &&
+true)' trigger exit when tt(foo) returns with a non-zero exit status.
+Note that if tt(foo) is a function, the option is also ignored during
+its whole execution.
+
+The option is also ignored when executing a complex command (tt(if),
+tt(for), tt(while), tt(until), tt(repeat), tt(case), tt(select),
+tt(always), or a list in braces) if its exit status comes from a
+command executed while the option is ignored. Hence, the tt(if)
+command in `tt(if true; then false && true; fi)' does not trigger
+exit.
+
+Finally, the option is also ignored while running initialization
+scripts and inside tt(DEBUG) traps.  In the latter case, the option is
+handled specially: it is unset on entry to the trap.  If the option
+tt(DEBUG_BEFORE_CMD) is set, as it is by default, and the option
+tt(ERR_EXIT) is found to have been set on exit, then the command for
+which the tt(DEBUG) trap is being executed is skipped.  The option is
+restored after the trap exits.
 
 Exiting due to tt(ERR_EXIT) has certain interactions with asynchronous
 jobs noted in
@@ -1756,28 +1764,27 @@ cindex(function return, on error)
 cindex(return from function, on error)
 item(tt(ERR_RETURN))(
 If a command has a non-zero exit status, return immediately from the
-enclosing function.  The logic is similar to that for tt(ERR_EXIT),
-except that an implicit tt(return) statement is executed instead of an
-tt(exit).  This will trigger an exit at the outermost level of a
-non-interactive script.  At the top level of an interactive shell,
-it will trigger a return to the command prompt; in other
-words, the sequence of commands typed by the user may be
-thought of as a function for this purpose.
-
-Normally this option inherits the behaviour of tt(ERR_EXIT) that
-code followed by `tt(&&)' `tt(||)' does not trigger a return.  Hence
-in the following:
-
-example(summit || true)
-
-no return is forced as the combined effect always has a zero return
-status.
-
-Note. however, that if tt(summit) in the above example is itself a
-function, code inside it is considered separately: it may force a return
-from tt(summit) (assuming the option remains set within tt(summit)), but
-not from the enclosing context.  This behaviour is different from
-tt(ERR_EXIT) which is unaffected by function scope.
+enclosing function.  Except for the exceptions described below, the
+logic is the same as that for tt(ERR_EXIT), except that an implicit
+tt(return) statement is executed instead of an tt(exit).  This will
+trigger an exit at the outermost level of a non-interactive script.
+At the top level of an interactive shell, it will trigger a return to
+the command prompt; in other words, the sequence of commands typed by
+the user may be thought of as a function for this purpose.
+
+Unlike for tt(ERR_EXIT), when a function is called while the option is
+being ignored, the option is NOT ignored during the execution of the
+function.  Hence, if tt(foo) in `tt(foo && true)' is a function, code
+inside it is considered separately: it may force a return from tt(foo)
+(assuming the option remains set within tt(foo)).
+
+Like for tt(ERR_EXIT), the option is ignored inside tt(DEBUG) traps
+but it's not unset on entry to the trap and setting or unsetting it
+inside the trap has no special effect.
+
+If tt(ERR_RETURN) and tt(ERR_EXIT) are both set, the latter takes
+precedence. Hence, exit rather than return is triggered when a command
+has a non-zero exit status.
 )
 pindex(EVAL_LINENO)
 pindex(NO_EVAL_LINENO)

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

* Re: [PATCH] Better ERR_EXIT and ERR_RETURN documentation
  2022-12-12 16:03 [PATCH] Better ERR_EXIT and ERR_RETURN documentation Philippe Altherr
@ 2022-12-12 16:21 ` Bart Schaefer
  2022-12-13  0:02   ` Philippe Altherr
  0 siblings, 1 reply; 3+ messages in thread
From: Bart Schaefer @ 2022-12-12 16:21 UTC (permalink / raw)
  To: Philippe Altherr; +Cc: Zsh hackers list

On Mon, Dec 12, 2022 at 8:04 AM Philippe Altherr
<philippe.altherr@gmail.com> wrote:
>
>> Except for the exceptions described below, the
>> logic is the same as that for tt(ERR_EXIT), except that an implicit
>> tt(return) statement is executed instead of an tt(exit).

That sentence is ... exceptional?  How about

  Except as explained below, an implicit tt(return) statement is
executed following the same logic described for tt(ERR_EXIT).

>> If tt(ERR_RETURN) and tt(ERR_EXIT) are both set, the latter takes
>> precedence. Hence, exit rather than return is triggered when a command
>> has a non-zero exit status.

Does this need to explain the interaction of the cases where ERR_EXIT
is ignored but ERR_RETURN is not?  As written it seems to imply that
exit would always occur in the cases where it would otherwise be a
return.


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

* Re: [PATCH] Better ERR_EXIT and ERR_RETURN documentation
  2022-12-12 16:21 ` Bart Schaefer
@ 2022-12-13  0:02   ` Philippe Altherr
  0 siblings, 0 replies; 3+ messages in thread
From: Philippe Altherr @ 2022-12-13  0:02 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list


[-- Attachment #1.1: Type: text/plain, Size: 1123 bytes --]

>
> That sentence is ... exceptional?


Yep, yep. I already cringed at the double except and now I notice the
"Except for the exceptions" 🙈

  Except as explained below, an implicit tt(return) statement is
> executed following the same logic described for tt(ERR_EXIT).


Awesome! So much better.

>> If tt(ERR_RETURN) and tt(ERR_EXIT) are both set, the latter takes
> >> precedence. Hence, exit rather than return is triggered when a command
> >> has a non-zero exit status.


> Does this need to explain the interaction of the cases where ERR_EXIT
> is ignored but ERR_RETURN is not?  As written it seems to imply that
> exit would always occur in the cases where it would otherwise be a
> return.


Good point. I rephrased as follows:

If tt(ERR_RETURN) and tt(ERR_EXIT) are both set, it may happen that
both exit and return should be triggered. In that case only exit is
triggered.

This implicitly covers the special case. I hope it's not necessary to
explain it explicitly as it's a rather corner case and it would
significantly increase the length of the explanation.

Philippe

[-- Attachment #1.2: Type: text/html, Size: 2027 bytes --]

[-- Attachment #2: patch-errexit-documentation-update.txt --]
[-- Type: text/plain, Size: 4718 bytes --]

diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index e92969531..cbd3d0f8e 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -1723,22 +1723,30 @@ pindex(NOERREXIT)
 cindex(exit status, trapping)
 item(tt(ERR_EXIT) (tt(-e), ksh: tt(-e)))(
 If a command has a non-zero exit status, execute the tt(ZERR)
-trap, if set, and exit.  This is disabled while running initialization
-scripts.
-
-The behaviour is also disabled inside tt(DEBUG) traps.  In this
-case the option is handled specially: it is unset on entry to
-the trap.  If the option tt(DEBUG_BEFORE_CMD) is set,
-as it is by default, and the option tt(ERR_EXIT) is found to have been set
-on exit, then the command for which the tt(DEBUG) trap is being executed is
-skipped.  The option is restored after the trap exits.
-
-Non-zero status in a command list containing tt(&&) or tt(||) is ignored
-for commands not at the end of the list.  Hence
-
-example(false && true)
-
-does not trigger exit.
+trap, if set, and exit.
+
+The option is ignored when executing the commands following tt(while),
+tt(until), tt(if), or tt(elif), a pipeline beginning with tt(!), or
+any command other than the last in command list containing tt(&&) or
+tt(||).  Hence neither `tt(if foo; then true; fi)', nor `tt(foo &&
+true)' trigger exit when tt(foo) returns with a non-zero exit status.
+Note that if tt(foo) is a function, the option is also ignored during
+its whole execution.
+
+The option is also ignored when executing a complex command (tt(if),
+tt(for), tt(while), tt(until), tt(repeat), tt(case), tt(select),
+tt(always), or a list in braces) if its exit status comes from a
+command executed while the option is ignored. Hence, the tt(if)
+command in `tt(if true; then false && true; fi)' does not trigger
+exit.
+
+Finally, the option is also ignored while running initialization
+scripts and inside tt(DEBUG) traps.  In the latter case, the option is
+handled specially: it is unset on entry to the trap.  If the option
+tt(DEBUG_BEFORE_CMD) is set, as it is by default, and the option
+tt(ERR_EXIT) is found to have been set on exit, then the command for
+which the tt(DEBUG) trap is being executed is skipped.  The option is
+restored after the trap exits.
 
 Exiting due to tt(ERR_EXIT) has certain interactions with asynchronous
 jobs noted in
@@ -1755,29 +1763,29 @@ pindex(NOERRRETURN)
 cindex(function return, on error)
 cindex(return from function, on error)
 item(tt(ERR_RETURN))(
+
 If a command has a non-zero exit status, return immediately from the
-enclosing function.  The logic is similar to that for tt(ERR_EXIT),
-except that an implicit tt(return) statement is executed instead of an
-tt(exit).  This will trigger an exit at the outermost level of a
-non-interactive script.  At the top level of an interactive shell,
-it will trigger a return to the command prompt; in other
-words, the sequence of commands typed by the user may be
-thought of as a function for this purpose.
-
-Normally this option inherits the behaviour of tt(ERR_EXIT) that
-code followed by `tt(&&)' `tt(||)' does not trigger a return.  Hence
-in the following:
-
-example(summit || true)
-
-no return is forced as the combined effect always has a zero return
-status.
-
-Note. however, that if tt(summit) in the above example is itself a
-function, code inside it is considered separately: it may force a return
-from tt(summit) (assuming the option remains set within tt(summit)), but
-not from the enclosing context.  This behaviour is different from
-tt(ERR_EXIT) which is unaffected by function scope.
+enclosing function. Except as explained below, an implicit tt(return)
+statement is executed following the same logic described for
+tt(ERR_EXIT). This will trigger an exit at the outermost level of a
+non-interactive script.  At the top level of an interactive shell, it
+will trigger a return to the command prompt; in other words, the
+sequence of commands typed by the user may be thought of as a function
+for this purpose.
+
+Unlike for tt(ERR_EXIT), when a function is called while the option is
+being ignored, the option is NOT ignored during the execution of the
+function.  Hence, if tt(foo) in `tt(foo && true)' is a function, code
+inside it is considered separately: it may force a return from tt(foo)
+(assuming the option remains set within tt(foo)).
+
+Like for tt(ERR_EXIT), the option is ignored inside tt(DEBUG) traps
+but it's not unset on entry to the trap and setting or unsetting it
+inside the trap has no special effect.
+
+If tt(ERR_RETURN) and tt(ERR_EXIT) are both set, it may happen that
+both exit and return should be triggered. In that case only exit is
+triggered.
 )
 pindex(EVAL_LINENO)
 pindex(NO_EVAL_LINENO)

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

end of thread, other threads:[~2022-12-13  0:03 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-12 16:03 [PATCH] Better ERR_EXIT and ERR_RETURN documentation Philippe Altherr
2022-12-12 16:21 ` Bart Schaefer
2022-12-13  0:02   ` Philippe Altherr

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

	https://git.vuxu.org/mirror/zsh/

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 NNTP newsgroup(s).