Re: Hiding specials, and namerefs

Philippe Altherr <[email protected]> Tue, 21 Jul 2026 02:46:08 +0200
Newsgroups gmane.comp.shells.zsh.devel
Message-ID <CAGdYchtAinCGigWFjq1uTawpuTsG+Zgb8w0gY2_JadhOXuaWtQ@mail.gmail.com>
--000000000000e607370657145902
Content-Type: text/plain; charset="UTF-8"

>
> -- `typeset -hn ...` is not allowed, but can be worked around, so
> probably should be allowed?


Indeed. Since -h is stating how the newly created parameter should coexist
with existing special ones with the same name, which sounds like something
that ought to be type independent, I don't see a good reason to disallow it
just for named references.

-- the ZLE parameters are already implicitly local on entry to a
> widget function


I assume that's what pm->level = locallevel + 1
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/Zle/zle_params.c#L206>
in
function makezleparams
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/Zle/zle_params.c#L194>
achieves.
When I first saw this line, it looked very bogus to me because it creates a
parameter whose level is greater than locallevel, which is in principle
forbidden. From your discussion, I infer that makezleparams is run just
before calling a Zle function and has the effect of declaring all the
parameters listed in zleparams
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/Zle/zle_params.c#L141>
as
if they had been declared locally in the Zle function. When the Zle
function returns, the normal end scope routine unsets and removes all the
parameters, which has the advantage that they never become visible to the
interactive command line.


Now, speaking of special parameters, could anyone explain to me what is
supposed to happen if one declares *without -h* a local parameter with the
same name as a special parameter?

The documentation suggests that without -h the local parameter keeps the
special effects of the enclosing special parameter. Apparently a new
parameter with its own state is created:

% () { echo $SECONDS; local SECONDS=10; echo $SECONDS; sleep 1; echo
$SECONDS }; echo $SECONDS
703041
10
11
703042

How is that possible? How can the new parameter have its own state but
still have the special effects? Is it because the local parameter reuses
the same gsu
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/zsh.h#L1857>
but gets its own u
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/zsh.h#L1841>?
Or, is the special paramater's u being saved, reused and restored when the
local parameter goes away?

For many special parameters, the state is stored in a dedicated C variable.
For example the Zsh HOME parameter
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/params.c#L320>
is backed by this C home variable
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/params.c#L91>.
I assume that a number of features that rely on the Zsh HOME parameter
directly access the C home variable. For instance, I assume that the cd
command accesses the C variable when it needs to know what the HOME
directory is. How is it possible to have multiple instances of the same
special parameter that each have their own state when there is a single C
variable to back them?

Local HOME parameters, like local SECONDS parameters, have their own state
but still keep the special effect of the global special parameter:

% zsh -c 'HOME=/etc; cd && pwd; () { local HOME=/tmp; cd && pwd }; cd &&
pwd'
/etc
/tmp
/etc

This shows that there are two states but apparently both are somehow
connected to the C home variable. Thanks to references, it's possible to
access both parameters from within the same scope. What is supposed to
happen if we try that?

% zsh -c 'HOME=/etc; cd && pwd; () { local -n GHOME=HOME; local HOME=/tmp;
cd && pwd; GHOME=/usr; cd && pwd; echo $HOME }; cd && pwd'
/etc
/tmp
zsh: segmentation fault

That code should certainly not segfault but it's not clear to me what it
should do. What directory should cd consider to be the home directory
after GHOME=/usr? And what should the value of the local HOME parameter be
after that assignment?

I haven't yet looked at the implementation. That's my next step to
understand what's going on but if anyone has an explanation of what is the
expected behaviour, it would be very welcome.

Philippe

--000000000000e607370657145902
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding=
-left:1ex">-- `typeset -hn ...` is not allowed, but can be worked around, s=
o<br>probably should be allowed?</blockquote><div><br></div><div>Indeed. Si=
nce -h is stating how the newly created parameter should coexist with exist=
ing special ones with the same name, which sounds like something that ought=
 to be type independent, I don&#39;t see a good reason to disallow it just =
for named references.</div><div><br></div><blockquote class=3D"gmail_quote"=
 style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);p=
adding-left:1ex">-- the ZLE parameters are already implicitly local on entr=
y to a<br>widget function</blockquote><div><br></div><div>I assume that&#39=
;s what=C2=A0<a href=3D"https://github.com/zsh-users/zsh/blob/3c0372aef88a6=
b7cc86f0902b1ba3f14a75118c9/Src/Zle/zle_params.c#L206"><font face=3D"monosp=
ace">pm-&gt;level =3D locallevel + 1</font></a>=C2=A0in function=C2=A0<a hr=
ef=3D"https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f1=
4a75118c9/Src/Zle/zle_params.c#L194">makezleparams</a>=C2=A0achieves. When =
I first saw this line, it looked very bogus to me because it creates a para=
meter whose level is greater than locallevel, which is in principle forbidd=
en. From your discussion, I infer that=C2=A0makezleparams=C2=A0is run just =
before calling a Zle function and has the effect of declaring all the param=
eters listed in=C2=A0<a href=3D"https://github.com/zsh-users/zsh/blob/3c037=
2aef88a6b7cc86f0902b1ba3f14a75118c9/Src/Zle/zle_params.c#L141">zleparams</a=
>=C2=A0as if they had been declared locally in the Zle function. When the Z=
le function returns, the normal end scope routine unsets and removes all th=
e parameters, which has the advantage that they never become visible to the=
 interactive command line.</div><div><br></div><div><br></div><div>Now, spe=
aking of special parameters, could anyone explain to me what is supposed to=
 happen if one declares <b>without -h</b> a local parameter with the same n=
ame as a special parameter?</div><div><br></div><div>The documentation sugg=
ests that without -h the local parameter keeps the special effects of the e=
nclosing special parameter. Apparently a new parameter with its own state i=
s created:</div><div><br></div><div><font face=3D"monospace">%=C2=A0() { ec=
ho $SECONDS; local SECONDS=3D10; echo $SECONDS; sleep 1; echo $SECONDS }; e=
cho $SECONDS</font></div><div><font face=3D"monospace">703041<br>10<br>11<b=
r>703042</font></div><div><br></div><div>How is that possible? How can the =
new parameter have its own state but still have the special effects? Is it =
because the local parameter reuses the same <a href=3D"https://github.com/z=
sh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/zsh.h#L1857"=
>gsu</a> but gets its own <a href=3D"https://github.com/zsh-users/zsh/blob/=
3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/zsh.h#L1841">u</a>? Or, is the=
 special paramater&#39;s=C2=A0u being saved, reused and restored when the l=
ocal parameter goes away?</div><div><br></div><div>For many special paramet=
ers, the state is stored in a dedicated C variable. For example the <a href=
=3D"https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a=
75118c9/Src/params.c#L320">Zsh HOME parameter</a> is backed by this <a href=
=3D"https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a=
75118c9/Src/params.c#L91">C home variable</a>. I assume that a number of fe=
atures that rely on the Zsh HOME parameter directly access the C home varia=
ble. For instance, I assume that the cd command accesses the C variable whe=
n it needs to know what the HOME directory is. How is it possible to have m=
ultiple instances of the same special parameter that each have their own st=
ate when there is a single C variable to back them?</div><div><br></div><di=
v>Local HOME parameters, like local SECONDS parameters, have their own stat=
e but still keep the special effect of the global special parameter:</div><=
div><br></div><div><font face=3D"monospace">% zsh -c &#39;HOME=3D/etc; cd &=
amp;&amp; pwd; () { local HOME=3D/tmp; cd &amp;&amp; pwd }; cd &amp;&amp; p=
wd&#39;</font></div><div><font face=3D"monospace">/etc<br>/tmp<br>/etc</fon=
t></div><div><br></div><div>This shows that there are two states but appare=
ntly both are somehow connected to the C home variable. Thanks to reference=
s, it&#39;s possible to access both parameters from within the same scope. =
What is supposed to happen if we try that?</div><div><br></div><div><font f=
ace=3D"monospace">% zsh -c &#39;HOME=3D/etc; cd &amp;&amp; pwd; () { local =
-n GHOME=3DHOME; local HOME=3D/tmp; cd &amp;&amp; pwd; GHOME=3D/usr; cd &am=
p;&amp; pwd; echo $HOME }; cd &amp;&amp; pwd&#39;<br>/etc<br>/tmp<br>zsh: s=
egmentation fault</font></div><div><br></div><div>That code should certainl=
y not segfault=C2=A0but it&#39;s not clear to me what it should do. What di=
rectory should cd consider to be the home directory after=C2=A0GHOME=3D/usr=
? And what should the value of the local HOME parameter be after that assig=
nment?</div><div><br></div><div>I haven&#39;t yet looked at the implementat=
ion. That&#39;s my next step to understand what&#39;s going on but if anyon=
e has an explanation of what is the expected behaviour, it would be very we=
lcome.</div><div><br></div><div>Philippe</div><div><br></div><div><br></div=
></div></div>

--000000000000e607370657145902--