Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: Issue with VAR=foo cmd where VAR is a named reference
- X-seq: zsh-workers 54944
- From: Philippe Altherr <philippe.altherr@xxxxxxxxx>
- To: Mikael Magnusson <mikachu@xxxxxxxxx>
- Cc: Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx>, Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: Re: Issue with VAR=foo cmd where VAR is a named reference
- Date: Fri, 10 Jul 2026 15:38:48 +0200
- Arc-authentication-results: i=1; mx.google.com; arc=none
- Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=Tts2ByXQPVok6oPQXG6i2snMv3EK2l9rdm2ft8blHWw=; fh=seVY/JVbq7l519SVVCe+52FiiiRrB1h5l++U6R433v0=; b=r/dDDjC0zIH/DqvRD03jdnodSXhFcx2nmGxu16eyqMCmer+4/TDVJs3N55jIohRIS1 oomoD6acGuBZQhQIAOCFcqjZrGzDabeypqV3eF5xY+wvB7GyEsNuVOe84om1Bj4kJir5 sf+dFAq/hmNp0YHHuprh3uCKTFinNMMuFwRNKdr6LVBge+XpFd+SOqWTKRutWGcOEReA i/wx/MpGxoStHKi4QGpO7DvTzfztj/ZtUzaBPInqCgLCYY7bOR4wyKrArrHpVOoxlVCd F1Qka+jh0DYE5G8JJK9WClxAguoOLb6mxLwLzTCglHjpAjYIzpqBOLdzwwjjafqf2xTX Snrw==; darn=zsh.org
- Arc-seal: i=1; a=rsa-sha256; t=1783690741; cv=none; d=google.com; s=arc-20260327; b=daFBwy1hbEZAl+0y1aWb+SXbD6Q7KV9ovSvtz0HFi/KFu+C3UrL6WdZVW1DntTZv2x luaFzDNinhRC36DbCjaCYREH1VW9+YvpEixF4VHzC1Q+bC6tUg/wjehJy9iySQWCdHh8 dBF9u32Vch69XhHlpIXOWkwra7y/t0Db+7JgTEsFKwZ2jPNQL/hVwN63y2ndFkswjsxd 4C979NAFHoPc36lxOe0AeDRIoTBcnBA7GO0gijmyJQlNj5SXDftb4Cw8cfLkdxzQFcsb Vyk54k/wTyIqeHb3qw1551l5jYx0lIzfF3P9ITZk2gmaBvUNOsFIcC7ACa1MAiiksNt+ z96w==
- Archived-at: <https://zsh.org/workers/54944>
- In-reply-to: <CAGdYchvto8bOjthzQXQ1K+_uXiRTuSnny1+=rd4e6az-3gw8aA@mail.gmail.com>
- List-id: <zsh-workers.zsh.org>
- References: <CAGdYchvh5Q+wG5au4=+-VDkZyvdu19-ac5gWsM-ZEGQm2_bgpw@mail.gmail.com> <CAH+w=7aapgt4Ag+ke-XHNy9XC8--nWH6eNTDWT=38PCHZUXk4g@mail.gmail.com> <CAGdYchsM9JbZT4W9qdGSB7eT6X-=WiCj1wmd_ynb=m9uSys5Hw@mail.gmail.com> <CAHYJk3ShjiOya2GnaoE+Jxh=24RU3kGvEWrf7YoDjt4Y300nGQ@mail.gmail.com> <CAGdYchvto8bOjthzQXQ1K+_uXiRTuSnny1+=rd4e6az-3gw8aA@mail.gmail.com>
Here is a proposal that is easy to implement and that avoids the existing problems (export of referred variables, broken restoration of hidden referred variables).
Bart suggested that "var=foo cmd" ought to be the same as running "cmd" in a scope augmented with an exported local "var" parameter: "() { local -x var=foo; cmd }". However, this is incompatible with the current behavior. Indeed, the type of the assigned parameters is preserved. For example, "typeset -i var; var=10+1 printenv var" is equivalent to "typeset -i var; () { local -x -i var=10+1; printenv var }". My proposal is to do the same for references, such that "typeset -n ref=foo; ref=bar cmd" is equivalent to "typeset -n ref=foo; () { local -n ref=bar; cmd }".
Inline assignments already differ from regular assignments by the fact that their changes are only temporary and only visible in the affected command. With my proposal they would additionally differ by the fact that no reference resolution is performed on the assigned parameters. In that sense, they would behave in the same way as for loops (e.g., "typeset -n ref=var; for ref in a b c; do … done" successively assigns "a", "b", and "c" to "ref" and not "var"). This proposal also matches ksh's behavior (in dynamic scopes):
% ksh -c 'function f { typeset -p ref; }; function g { typeset -n ref=foo; ref=bar f; typeset -p ref; }; g'
typeset -n -x ref=bar
typeset -n ref=foo
Philippe
diff --git a/Src/exec.c b/Src/exec.c
index 20caf40d1..a7a59f012 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -2571,6 +2571,7 @@ addvars(Estate state, Wordcode pc, int addflags)
* is implicitly scoped.
*/
flags = !(addflags & ADDVAR_RESTORE) ? ASSPM_WARN : 0;
+ flags |= addflags & ADDVAR_EXPORT ? ASSPM_NONAMEREF : 0;
xtr = isset(XTRACE);
if (xtr) {
printprompt4();
@@ -4477,7 +4478,7 @@ save_params(Estate state, Wordcode pc, LinkList *restore_p, LinkList *remove_p)
char *ss = itype_end(s, INAMESPC, 0);
int slen = *ss == '[' || *ss == Inbrack ? ss - s : strlen(s);
addlinknode(*remove_p, s = dupstring_wlen(s, slen));
- if ((pm = (Param) paramtab->getnode(paramtab, s))) {
+ if ((pm = (Param) realparamtab->getnode2(realparamtab, s))) {
Param tpm = NULL;
if (pm->env)
delenv(pm);
@@ -4525,7 +4526,7 @@ restore_params(LinkList restorelist, LinkList removelist)
/* remove temporary parameters */
while ((s = (char *) ugetnode(removelist))) {
- if ((pm = (Param) paramtab->getnode(paramtab, s)) &&
+ if ((pm = (Param) realparamtab->getnode2(realparamtab, s)) &&
!(pm->node.flags & PM_SPECIAL)) {
pm->node.flags &= ~PM_READONLY;
unsetparam_pm(pm, 0, 0);
@@ -4536,7 +4537,8 @@ restore_params(LinkList restorelist, LinkList removelist)
/* restore saved parameters */
while ((pm = (Param) ugetnode(restorelist))) {
if (pm->node.flags & PM_SPECIAL) {
- Param tpm = (Param) paramtab->getnode(paramtab, pm->node.nam);
+ Param tpm =
+ (Param) realparamtab->getnode2(realparamtab, pm->node.nam);
DPUTS(!tpm || PM_TYPE(pm->node.flags) != PM_TYPE(tpm->node.flags) ||
!(pm->node.flags & PM_SPECIAL),
@@ -4565,7 +4567,7 @@ restore_params(LinkList restorelist, LinkList removelist)
}
pm = tpm;
} else {
- paramtab->addnode(paramtab, pm->node.nam, pm);
+ realparamtab->addnode(realparamtab, pm->node.nam, pm);
}
if ((pm->node.flags & PM_EXPORTED) && ((s = getsparam(pm->node.nam))))
addenv(pm, s);
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index 1ed21906f..c9d920196 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -2402,4 +2402,20 @@ F:converting from association/array to string should work here too
>typeset -n ref1=var
>typeset -n ref2
+ show() { typeset -p var ref }
+ typeset var=foo
+ typeset -n ref=var
+ ref=bar show
+ typeset -p var ref
+ echo var=$(ref=bar printenv var)
+ echo ref=$(ref=bar printenv ref)
+ unfunction show
+0:reference inline assignment assigns the reference
+>typeset -g var=foo
+>typeset -g -n ref=bar
+>typeset var=foo
+>typeset -n ref=var
+>var=
+>ref=
+
%clean
Messages sorted by:
Reverse Date,
Date,
Thread,
Author