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

Re: `return` does not behave properly under `!`



Hi Stephane and Bart (reply inline below, as it's relevant to Stephane),

On 2022-12-07 at 08:42:55 AM, Stephane Chazelas wrote:

> 2022-12-06 13:18:59 -0500, Michael Greenberg:
> [...]
>> i() {
>>   ! return 9
>>   echo fail not
>> }
>> i
>> echo $?
>> ```
> [...]
>> 0
> [...]
>
> That:
>
> ! return n
>
> Behaves like return !n (and ! return behave like return !$? (or
> return "$(( ! $? ))" in POSIX syntax) doesn't sound totally off
> to me. As written, I would say the POSIX spec may even be
> requiring it.

Here's what the POSIX spec says about `return`:

  The return utility shall cause the shell to stop executing the
  current function or dot script. If the shell is not currently
  executing a function or dot script, the results are unspecified.

  ...

  EXIT STATUS

  The value of the special parameter '?' shall be set to n, an unsigned
  decimal integer, or to the exit status of the last command executed if
  n is not specified. If n is not an unsigned decimal integer, or is
  greater than 255, the results are unspecified. When return is executed
  in a trap action, the last command is considered to be the command
  that executed immediately preceding the trap action.

And here's what it says about `!` on pipelines:

  If the pipeline does not begin with the ! reserved word, the exit
  status shall be the exit status of the last command specified in the
  pipeline. Otherwise, the exit status shall be the logical NOT of the
  exit status of the last command. That is, if the last command returns
  zero, the exit status shall be 1; if the last command returns greater
  than zero, the exit status shall be zero.

So my reading is the opposite: `return` doesn't have an exit status,
because it causes the currently executing function (or sourced script)
to terminate; it does, however, set $?. So `!` shouldn't affect it.

But even without a close reading of the spec, it's just not how early
return works in any language. Having the evaluation context beyond
`return` affect the returned value subverts the early and immediate
return---and, in so doing, invites bugs.

So far, dash, yash, and zsh are the only shells I've found with this
behavior, and the dash folks seem to agree that it's an undesirable
bug. And also...

On 2022-12-06 at 08:53:25 PM, Bart Schaefer wrote:

> On Tue, Dec 6, 2022 at 10:19 AM Michael Greenberg
> <michael@greenberg.science> wrote:
>>
>> Following up an example from Harald van Dijk on the dash mailing list, I
>> discovered that zsh does not `return` properly under a `!`.
>
> This appears to have been fixed by Philippe Altherr's series of
> patches for ERR_EXIT et al, zsh-workers 51001, 51071, 51076.

Ah---thank you! I wish there were a straightforward fulltext search of
the archives (though I don't know I would have found this anyway, as it
doesn't explicitly mention `return`). I'll try to test these patches to
confirm.

> That's consistent with ! break causing the while/until loop it's
> in returning with failure which I've seen code rely upon (AFAIK,
> that's the only way to get those loops to return with failure;
> doesn't work in pdksh and derivatives though).

That seems hardly relevant here: a return explicitly sets $?, unlike
break/continue (which both have exit statuses, unlike return).

Cheers,
Michael




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