On Thu, 4 Sept 2025 at 23:56, Chet Ramey <[email protected]> wrote:

> > $ declare -in foo
> > $ printf '%s\n' "${?}"
> > 0
> > $ foo=bar
> > $ printf '%s\n' "${?}"
> > 0
> > $ declare -p foo
> > declare -in foo="0"
> > $ printf '%s\n' "${?}"
> > 0
> > $ foo=12
> > bash: `0': not a valid identifier
> > $ printf '%s\n' "${?}"
> > 1


I think my first reaction to this is … Eeeeeeeeeeeeeeeek! That's horrifying!

(and here I thought I had developed a reasonable immunity to the
Eldritch Horrors that lurk within the shell language; seems I was wrong)

This is a straightforward application of the nameref rules.


*Whenever the nameref variable is referenced, assigned to, unset, or has
its attributes modified (other than  using or changing the nameref
attribute itself), the operation is actually performed on the variable
specified by the nameref variable's value.*

Or did I miss the bit where it says there's different behaviour when the
nameref is empty and/or unset? (And no, the assignment/binding within the «
declare » statement itself need not count as such; there's already
precedent where « declare -r var=val » sets the value and *then* attaches
the read-only attribute, so it's quite natural to assume that « declare -n
var=othervar » works the same way. If it doesn't yet, maybe it ought to?

A straightforward application of these rules would seem to imply that
assigning to a nameref which isn't already bound to a valid variable or
array element will result in a complaint about an invalid reference. (It
could be unset, empty, or set to something that's not a valid variable name
or array expression.)

Treating the first assignment to a nameref as a binding (change of
referent) seems suboptimal for code stability. The safer thing to do would
be to only allow binding within a declare/local/typeset command, or a "for"
loop.

That said, somebody somewhere will be using the existing behaviour, so I
expect that a new restriction couldn't be enacted without proactive buy-in
from the code in question (e.g. « set -U » as a stronger version of « set
-u »?).



Separately, I've been wondering about a completely different approach to
namerefs. Rather than being a declared property of the variable, make
binding a clearly different operation from assignment; one possible syntax
might look like this:

$ foo:=bar
$ foo=1
$ echo $bar
1
$ bar=2 zot=3
$ echo $foo $bar $zot
2 2 3
$ for r: in foo bar zot ; do echo $r ; done
2
2
3
$ foo:=
$ echo ${foo-Unset}
Unset

-Martin

Reply via email to