That said, there's also the total lack of a mechanism for doing controlled
descent into the nameref chain that has always been a problem. It would be
really nice to also have a non-terrible way to introspect if not manipulate the
non-leaf variables (without changes to the normal expected functioning.)
There are mechanisms to introspect named references. Could you be more explicit on what you are missing?
Let's consider the following definitions:
$ local var=foo
$ local -n ref1=var
$ local -n ref2=ref1
You can use typeset -p to introspect the chain of references:
$ typeset -p ref2
typeset -n ref2=ref1
The -n tells us that ref2 is a reference and ref1 is what it's pointing to. You can then repeat the same until you reach a non-reference variable:
$ typeset -p ref1
typeset -n ref1=var
$ typeset -p var
typeset var=foo
An alternative is to rely on the (!) and the (t) expansion flags. The former prevents the dereferencing and the latter returns a description of the variable instead of its content.
echo "ref2 : ${(!t)ref2} = ${(!)ref2}"
ref2 : nameref = ref1
This tells us that ref2 is a reference pointing to ref1. The same can be repeated until a non-reference variable is reached:
echo "ref1 : ${(!t)ref1} = ${(!)ref1}"
ref1 : nameref = var
echo "var : ${(!t)var} = ${(!)var}"
var : scalar = foo
This shows that there are basic mechanisms to introspect references and even chains of references. The only shortcoming I'm aware of is that these mechanisms fail if some of the involved variables are hidden.
For instance, if we try to inspect the chain defined above in a function where ref1 is hidden, both mechanism would let us think that ref2 refers to the variable hiding the reference ref1:
$ () {
local ref1=hide-upper-ref1
typeset -p ref2
typeset -p ref1
echo "ref2 : ${(!t)ref2} = ${(!)ref2}"
echo "ref1 : ${(!t)ref1} = ${(!)ref1}"
}
typeset -g -n ref2=ref1
typeset ref1=hide-upper-ref1
ref2 : nameref = ref1
ref1 : scalar-local = hide-upper-ref1
From this we would infer that $ref2 expands to hide-upper-ref1, while in reality it expands to foo.
In my opinion, it would be great that even chains of references involving hidden variables could be introspected. It would require a few extra features. Afaict, it's all pretty trivial to implement. If there is interest, I can go more into details into what I think would be needed.
Philippe
On 2025-11-30 13:03, Philippe Altherr wrote:
> *Issue 2: reference to subscripted **reference*
>
> When a reference A references a subscripted referent B that is itself a
> reference, expansions of A wrongly apply the subscript to the content of B
> (i.e., the name of the variable referred by B) instead of applying it to
> the content of the variable referred by B:
>
> $ var=XYZ; local -n ref1=var ref2=ref1[2]; echo ref2=$ref2
> ref2=a
> $ arr=(X Y Z); local -n ref1=arr ref2=ref1[2]; echo ref2=$ref2
> ref2=r
>
> Assignments to A wrongly modify the content of B instead of modifying the
> content of the variable referred by B:
>
> $ var=XYZ; local -n ref1=var ref2=ref1[2]; ref2=abc; typeset -p var ref1
> typeset -g var=XYZ
> typeset -n ref1=vabcr
> $ arr=(X Y Z); local -n ref1=arr ref2=ref1[2]; ref2=abc; typeset -p arr ref1
> typeset -g -a arr=( X Y Z )
> typeset -n ref1=aabcr
>
> In both cases, the reason is, as Bart commented in workers/54076
> <https://zsh.org/workers/54076>, because resolve_nameref()
> <https://github.com/zsh-users/zsh/blob/5539bc3fd59a2577bf1f951430c20e2b1e7b4dce/Src/params.c#L6353>(wrongly)
> assumes that a subscripted referent must be the stopping point, and so
> returns its input.
>
> *Discussion*
>
> The examples above are unlikely to occur as such in any real script.
> However, it's not difficult to come up with more real life scenarios that
> trigger the same issues; references to subscripted variables look very
> brittle to me. It's not far-fetched to think that many users who try to use
> them would be affected by at least one of these issues.
It's a problem. Regular nameref users would definitely hit this eventually. Not
to mention badly clashing with the historical design.
That said, there's also the total lack of a mechanism for doing controlled
descent into the nameref chain that has always been a problem. It would be
really nice to also have a non-terrible way to introspect if not manipulate the
non-leaf variables (without changes to the normal expected functioning.)