Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: { exit } always { foo }



Bart Schaefer wrote on Tue, Dec 17, 2019 at 20:54:44 -0800:
> On Tue, Dec 17, 2019 at 7:57 PM Daniel Shahaf <d.s@xxxxxxxxxxxxxxxxxx> wrote:
> >
> > Which is correct, the manual or the test?
> 
> I think both are, although the wording in the doc might be clearer.
> This is the important bit (my capitals):
> 
> >     An tt(exit) command (or a tt(return) command executed AT THE OUTERMOST
> >     function LEVEL of a script) encountered in tt(try-list) does em(not) cause
> >     the execution of var(always-list).  Instead, the shell exits immediately
> >     after any tt(EXIT) trap has been executed.

The way I read this is, it says that such-and-such will happen whenever
_either_ of the following two constructs is seen:

- 'exit' is invoked by try-list (possibly in a deep callee)

- 'return' is invoked, outside of any function, in a try-list

That is, the "at the outermost level" qualifier applies only to 'return', not
to 'exit'.  This interpretation is supported by the parentheses.  (This is one
of the rare cases in which English is explicit about its syntactic precedece rules.)

Under this reading, the docs promise that the test's behaviour will be the same regardless
of whether or not the 'exit' happens to be in a function.

> In this line:
> >   725     mytest() { { exit 3 } always { mywrap }; print Exited before this }
> 
> The always block is NOT at the outermost level, so the shell does not
> exit immediately.  "Outermost" means that there IS NO surrounding
> function scope.  Thus in the following case:
> 
>  (
>   mywrap() { echo BEGIN; true; echo END }
>   { exit 3 } always { mywrap }; print Exited before this
>  )
> 
> The always block is not executed and mywrap isn't called.  As soon as
> you put the "always" inside the "mytest" scope, that rule no longer
> applies.

Good catch.  Based on the manual, I would have expected such a difference to
manifest if the two cases had used 'return 3', but not if they used 'exit 3'.

Furthermore, it makes intuitive sense for 'return' to behave in one way inside
a function, and in another way — like 'exit' — when not inside a function; but
I don't immediately see why it makes sense for 'exit' to change behaviour
depending on when it's inside a function or not.  Compare:

1.
    mywrap() { echo BEGIN; true; echo END }
        { exit 3 } always { mywrap }; print Exited before this

2.
    mywrap() { echo BEGIN; true; echo END }
    (){ { exit 3 } always { mywrap }; print Exited before this }

So, personally, I would find it more intuitive to change the implementation to
match the documentation, than the other way around.

Bart Schaefer wrote on Tue, Dec 17, 2019 at 20:59:01 -0800:
> On Tue, Dec 17, 2019 at 8:54 PM Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
> >
> > The word "function" there is unfortunate because it doesn't mean a
> > shell function.
> 
> Well, strictly I guess it does mean a shell function because that's
> the only way to introduce another scope, but it's confusing to think
> of "the level where no shell function has been introduced yet" as a
> "function level".  It's sort of like calling the sidewalk in front of
> a building the "outermost floor".

It's intuitive enough to me.  It's pretty common in math contexts, too: for
example, one can scale down quadratic equations and linear equations to
zeroth-degree equations (a₀⋅x⁰ = 0, solve for $x$).  Makes perfect sense.
(No promises about usefulness, though.)

Cheers,

Daniel



Messages sorted by: Reverse Date, Date, Thread, Author