Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
nameref binding not finding calling-scope vars?
- X-seq: zsh-workers 53417
- From: Phil Pennock <zsh-workers+phil.pennock@xxxxxxxxxxxx>
- To: Zsh Workers <zsh-workers@xxxxxxx>
- Subject: nameref binding not finding calling-scope vars?
- Date: Sat, 29 Mar 2025 03:19:14 -0400
- Archived-at: <https://zsh.org/workers/53417>
- List-id: <zsh-workers.zsh.org>
- Mail-followup-to: Zsh Workers <zsh-workers@xxxxxxx>
- Openpgp: url=https://www.security.spodhuis.org/PGP/keys/key2020-cv25519.asc
Say we want a function to set a variable whose name is given to it, so
we use a nameref. We want to set the variable to be an array, even if
outside it exists as a non-array.
This has been confirmed with zsh head rebuilt today, 435cb1b748
(2025-03-03) plus one local completion patch, so current.
Tested under `zsh -f`.
% inner() { local -n var="${1:?}"; typeset -ga var=(alpha beta gamma); }
% typeset -p foo; inner foo; typeset -p foo
typeset: no such variable: foo
typeset -a foo=( alpha beta gamma )
That's fine. The docs for 'typeset -g' say:
> Note that this does not necessarily mean that the parameter will be
> global, as the flag will apply to any existing parameter (even if
> unset) from an enclosing function.
% outer() { local -a foo=(); inner foo; typeset -p foo }
% foo=3
% typeset -p foo; outer foo; typeset -p foo
typeset foo=3
typeset -g -a foo=( alpha beta gamma )
typeset -a foo=( alpha beta gamma )
This seems wrong. `outer()` declared foo to be local, so inner should
not have been able to reset it back to being at global scope, that final
line should have shown foo=3, AIUI.
So what if we drop the `typeset -ga`? We can't use typeset on the
referred-to variable through the nameref without '-g' because then the
value will be local, but we can assign in the parent scope?
`outer` sets foo to be an array, so that should be fine?
% inner() { local -n var="${1:?}"; var=(alpha beta gamma); }
% foo=3
% typeset -p foo; outer foo; typeset -p foo
typeset foo=3
inner: foo: attempt to assign array value to non-array
So using a nameref seems to ignore up-callstack local variables?
The nameref seems to be treating parent locals as private, not local?
The docs have been improved since before I rebuilt; so I'd been reading
the docs as of commit a528af5c57 (2023-12-16) and now has discussion of
`-u` to find in the parent scope.
% inner() { local -un var="${1:?}"; var=(alpha beta gamma); }
% foo=3
% typeset -p foo; outer foo; typeset -p foo
typeset foo=3
inner: foo: attempt to assign array value to non-array
My use-case is a function which can take a `--set-var=VARNAME` flag, to
use something other than $reply, and so set an arbitrary variable to an
array. The caller function should be able to have a local variable and
ask for it to be set. That doesn't seem to work.
Am I missing something or are there some rough edges here still?
ksh93:
$ echo $KSH_VERSION
Version AJM 93u+ 2012-08-01
$ function inner { typeset -n var="${1:?}"; var=(alpha beta gamma); }
$ function outer { typeset -a foo; foo=(); inner foo; typeset -p foo; }
$ foo=3
$ typeset -p foo; outer foo; typeset -p foo
foo=3
typeset -a foo=(alpha beta gamma)
foo=3
$
bash:
$ echo $BASH_VERSION
5.0.17(1)-release
$ inner() { local -n var="${1:?}"; var=(alpha beta gamma); }
$ outer() { local -a foo=(); inner foo; typeset -p foo; }
$ foo=3
$ typeset -p foo; outer foo; typeset -p foo
declare -- foo="3"
declare -a foo=([0]="alpha" [1]="beta" [2]="gamma")
declare -- foo="3"
Messages sorted by:
Reverse Date,
Date,
Thread,
Author