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

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



On 2022-12-07 at 04:01:13 PM, Stephane Chazelas wrote:

> 2022-12-07 10:05:34 -0500, Michael Greenberg:
>> Hi Stephane and Bart (reply inline below, as it's relevant to Stephane),
> [...]
>> 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.
> [...]
>
> Agreed.
>
>> 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.
> [...]
>
> Agreed.
>
>> 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...
>
> Also bosh.
>
> I can't see why one would call ! return if not to expect that to
> have an effect on the exit status.
>
> $ zsh -c 'f() { ! { false || return; }; }; f; echo "$?"'
> 0
>
> Is more of a problem though and I agree would be an undesirable bug..

Like in your example, I think the pernicious case is when the ! and the
return are far apart. The scenario I imagine is something like:

f() {
  while ! { SOME_CONDITION_FOR_EARLY_EXIT && return 1 
            SOME_CONDITION_FOR_TERMINATION_WITH_POSTPROCESSING 
          }
  do 
    ...
  done
  ...
}

In process of running the loop's predicate, the script might realize
that it's just time to exit the function early (without
postprocessing). The outer negation in the predicate is meant to negate
the whole predicate, not the return. It would be surprising to have that
distant `!` affect the return (and having it negate the status would
make it impossible to return statuses other than 0 and 1 in this form).

>
> [...]
>> 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.
>
> You can download and rsync the full archive from
> rsync://rsync.zsh.org/mla/zsh-workers/

Oh---I didn't realize this rsync interface existed, thank you! Might be
good to document it on https://www.zsh.org/mla/.

>> That seems hardly relevant here: a return explicitly sets $?, unlike
>> break/continue (which both have exit statuses, unlike return).
> [...]
>
> They're still special builtins that break the flow, so I would
> still consider it relevant. I've not checked zsh recently but
> there are funny things you can do with some shells by calling
> break/continue in a function where the corresponding "enclosing"
> loop is in one of the callers. IIRC there was some POSIX
> discussion about that and the text tightened.

Yes, non-lexical break is a mess, with varying treatment in popular
shells (e.g., bash and dash disagree). Having ! affect return from a
distance amounts to a form of non-lexical return munging. As someone who
studies programming languages for a living, I would very much advise
against non-lexical control if we can avoid it. :)

I think there's a good opportunity to have shells in alignment here (and
maybe make POSIX more explicit): if zsh folks agree that return should
not be affected by an enclosing !, we can align bash/dash/zsh. (I'm
hopeful yash folks will agree, too.)

Cheers,
Michael




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