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

Re: Up-scope named references, vs. ksh



2024-02-20 14:30:56 -0800, Bart Schaefer:
> On Tue, Feb 20, 2024 at 1:05 PM Stephane Chazelas <stephane@xxxxxxxxxxxx> wrote:
> >
> > 2024-02-17 19:26:07 -0800, Bart Schaefer:
> > [...]
> > >  A) Src/zsh -c 'function f { typeset -n ref; ref=$1; typeset var=foo;
> > > ref=X; echo "$ref ${(!)ref} $var"; }; f var; echo "$var"'
> >
> > Note that the ksh93 man page mentions:
> >
> > ksh93> Note  that,  for this to work, the positional parameter must be
> > ksh93> assigned directly to the nameref as part of the declaration command
> > ksh93> [...]   For instance, typeset -n var; var=$1
> > ksh93> won't cross that barrier
> 
> And yet, after replacing ksh2020 with Version AJM 93u+ 2012-08-01

With recent maintained versions with all the bug fixes, it would
look something like:

$ ./arch/linux.i386-64/bin/ksh -c 'echo ${.sh.version}'
Version AJM 93u+m/1.1.0-alpha+b8e3d2a4 2024-02-17

The one on Ubuntu 22.04 has:

$ ksh -c 'echo ${.sh.version}'
Version AJM 93u+m/1.0.0-beta.2 2021-12-17

93u+ 2012-08-01 would be the one from AT&T without the later bug
fixes.

> ksh -c 'function f { typeset -n ref; ref=$1; typeset var=foo;
> ref=X; echo "$ref ${!ref} $var"; }; f var; echo "$var"'
> X var foo
> X
> 
> So it sure looks like the barrier was crossed in a case where the doc
> stated it would not be.

But in that case, you're referencing a variable from the global
scope, not the local scope from a parent function.

[...]
> > The only remaining problem is when the refered variable
> > is not set/declared.
> 
> It IS possible to make that "typeset -g" implicit, but that has other
> potential effects such as creating an (unset) parameter in global
> scope (triggering WARN_CREATE_GLOBAL?).  If the parameter already has
> been declared in a calling function scope, then even with the -g, the
> nameref will point to that one, even if it's more than one level up
> the call chain.  Which ought to be what you expect from dynamic
> scoping.
> 
> > Contrary to mksh or bash, it alread gets this right:
> 
> Yes, as soon as an existing parameter is found the nameref records
> what scope contains that parameter and looks for it there when
> (de)referenced.  The glitchy bit is when there is no existing
> parameter from which to obtain a scope.  I'm reluctant to try to make
> this too magical, which is why I lean toward asking function authors
> to explicitly do the "typeset -g $1" when that's what they mean.
> Could certainly add this to the doc.
[...]

I have no notion of how zsh variables are implemented so I'm
probably talking rubish and it's hard to think this whole thing
through, but it seems to me that for a nameref variable, upon
typeset -n ref=var, zsh should record at that point what scope
or level of the stack the var is to be found and keep that
record for the duration of the scope where that nameref is
defined or until the next typeset -n ref=anything in the same
scope.

Like:
- if var is found (declared) in the current scope, record that
  it's that of that scope that it is to get the value of or set
  or unset (and reset again thereafter)
- if not, repeat for parent scope
- if not found at all, record that it's to be at the global
  scope.

Like in:

f() { typeset a; unset a; g; echo "$a"; }
g() { h; }
h() { 
  typeset b=x
  typeset -n r1=a r2=b r3=c
  typeset a=foo c=bar
  r1=x r2=y r3=z
  unset r{1..3}
  r1=x r2=y r3=z
}
f

r1=x sets the $a of f, r2=y sets the $b of h, and r3=z sets a
global $c both times.

[...]
> So did I.  I await with gritted teeth the first time that Ray forgets
> to declare his loop variable with a nameref of the same name in scope.
[...]

Yes, difficult decision to choose between
- cleaner design, align with mksh
- align with original design in ksh93 and bash which already
  copied it (well, that part).

-- 
Stephane




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