help / color / mirror / code / Atom feed
From: Bart Schaefer <schaefer@brasslantern.com>
To: Zsh hackers list <zsh-workers@zsh.org>
Subject: Re: [PATCH 1/3]: Add named references
Date: Sat, 11 Feb 2023 15:43:13 -0800	[thread overview]
Message-ID: <CAH+w=7YN_i9KxgZFFn1zNe98pT0KmErdpHNZr_oAWf5CpwsgSg@mail.gmail.com> (raw)
In-Reply-To: <CAH+w=7aKwKhdXjPo2FQG1GqjHQzX=5to_m6kZeL-UFfQh_XMtw@mail.gmail.com>

On Fri, Feb 10, 2023 at 11:45 PM Bart Schaefer
<schaefer@brasslantern.com> wrote:
> On Fri, Feb 10, 2023 at 11:02 PM Oliver Kiddle <opk@zsh.org> wrote:
> >
> > I'd be
> > fine with the reference becoming unset at the time of the return if it
> > refers to a variable that is going out of scope. Can that be done as
> > part of the same code that drops the local variables?

That's actually a little startling given dynamic scoping.  It leads to this:

  typeset -n ref=var
  () {
    typeset -p ref
  typeset -p ref

typeset -g -n ref=var
typeset: no such variable: ref

If the called function were a blackbox, it would be extremely puzzling
why "ref" became unset.

The additional complication is that the parameter table is a hash, so
it's scanned in random order; we can't be sure that the referent local
$var will be found and unset before the referring $ref is examined.  I
suppose we could scan twice (ick).

Instead let's think for a moment about how the dynamic scoping works.
"ref" has two properties:  The locallevel at which it was declared,
and the locallevel at which it prefers to find a referent.  Any time
you use $ref (or assign to ref) the search starts at the current
locallevel and proceeds upward until either the preferred level is
reached or the "topmost" defined parameter is found, whichever comes

So ... if endparamscope() walks the preferred referent locallevel
upward as the scope unwinds, we get (using your earlier example with
my addition):

  typeset -n ref
  () {
    typeset var=x
    echo $ref
  typeset -p ref
  echo $ref
  () {
   typeset var=y
   echo $ref
   () {
     typeset var=z
     echo $ref

typeset -n ref=var

The inner assignment to ref changes the scope , but it then unwinds so
in the second function (which does not assign to ref) it is back to
pointing at the original scope, and finds $var there.

If "var=hello" is replaced by "unset var" (so there is no parameter at
the original scope), then the output is:

typeset -n ref=var


This is because the assignment "ref=var" has initialized the name to
which "ref" points, but there is no such name at the same level, so
the nearest parameter of the same name is chosen.

If "typeset -n ref" at the top level is replaced by "typeset -n
ref=var" then the "ref=var" assignment in the first function changes
the value of either the global $var or the local $var from "x" to
"var" (depending on which existed first) because ref already has a
referent name.  So the output could be either:

# with var=hello
typeset -n ref=var

# with var unset
typeset -n ref=var


Given the requirements that (1) assigning a value to a nameref that
has no referent initializes the nameref (required for "for" loop) and
(2) dynamic scoping selects the best referent by name, I think this is
the best I can do without something even more surprising.

The other option that occurs to me is for the assignment ref=var to
automatically create a local $ref (as if "typeset ref=var" had been
used).  That would then be unwound and we'd end up back in the
original state.  But that would also be unexpected behavior in dynamic

  reply	other threads:[~2023-02-11 23:43 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-06  2:21 Bart Schaefer
2023-02-08  3:45 ` Oliver Kiddle
2023-02-08  4:59   ` Bart Schaefer
2023-02-08 23:16     ` Bart Schaefer
2023-02-09  0:47     ` Oliver Kiddle
2023-02-09  2:01       ` Oliver Kiddle
2023-02-09  5:45         ` Bart Schaefer
2023-02-09  4:49       ` Bart Schaefer
2023-02-09 20:49         ` Oliver Kiddle
2023-02-09 23:07           ` Bart Schaefer
2023-02-11  3:04             ` Bart Schaefer
2023-02-11  3:55               ` Bart Schaefer
2023-02-11  5:36                 ` Speaking of dangerous referents Bart Schaefer
2023-02-12  8:00                   ` Oliver Kiddle
2023-02-12  8:34                     ` Bart Schaefer
2023-02-11  7:02               ` [PATCH 1/3]: Add named references Oliver Kiddle
2023-02-11  7:45                 ` Bart Schaefer
2023-02-11 23:43                   ` Bart Schaefer [this message]
2023-02-11 23:45                     ` Bart Schaefer
2023-02-12  7:38                     ` Oliver Kiddle
2023-02-12  9:02             ` Oliver Kiddle
2023-02-12 18:59               ` Bart Schaefer
2023-02-12 19:45                 ` PM_* flags in zsh.h (was Re: [PATCH 1/3]: Add named references) Bart Schaefer
2023-02-12 21:01                   ` Oliver Kiddle
2023-02-12 22:54                 ` [PATCH 1/3]: Add named references Oliver Kiddle

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:

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

  git send-email \
    --in-reply-to='CAH+w=7YN_i9KxgZFFn1zNe98pT0KmErdpHNZr_oAWf5CpwsgSg@mail.gmail.com' \
    --to=schaefer@brasslantern.com \
    --cc=zsh-workers@zsh.org \


* 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


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).