zsh-workers
 help / color / mirror / code / Atom feed
From: Michael Greenberg <michael@greenberg.science>
To: Stephane Chazelas <stephane@chazelas.org>
Cc: Bart Schaefer <schaefer@brasslantern.com>, zsh-workers@zsh.org
Subject: Re: `return` does not behave properly under `!`
Date: Wed, 07 Dec 2022 12:10:55 -0500	[thread overview]
Message-ID: <m2cz8vp2ao.fsf@rocinante.lan> (raw)
In-Reply-To: <20221207160113.ol3lcbm6p7xu3rru@chazelas.org>

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


  parent reply	other threads:[~2022-12-07 17:23 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-06 18:18 Michael Greenberg
2022-12-07  4:53 ` Bart Schaefer
2022-12-07  8:42 ` Stephane Chazelas
2022-12-07 15:05   ` Michael Greenberg
2022-12-07 16:01     ` Stephane Chazelas
2022-12-07 16:16       ` Peter Stephenson
2022-12-07 17:06         ` Bart Schaefer
2022-12-07 17:21           ` Peter Stephenson
2022-12-07 18:51             ` Bart Schaefer
2022-12-07 17:10       ` Michael Greenberg [this message]
2022-12-09 15:22         ` Michael Greenberg
2022-12-09 16:21           ` Bart Schaefer
2022-12-09 19:20             ` Michael Greenberg
2022-12-07 16:08     ` Bart Schaefer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=m2cz8vp2ao.fsf@rocinante.lan \
    --to=michael@greenberg.science \
    --cc=schaefer@brasslantern.com \
    --cc=stephane@chazelas.org \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).