bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: "local -g" declaration references local var in enclosing scope


From: Adrian Ho
Subject: Re: "local -g" declaration references local var in enclosing scope
Date: Mon, 11 Mar 2024 20:26:46 +0800

Thanks much for all the insights, everyone! Indeed, the man page isn't
clear on how to reason about `local -g`. I'm now left with the following
understanding:

1. There is *nothing local* about `local -g`; it operates entirely at the
global level. In particular, it does *not* create a local reference to a
global var, which is the natural assumption given the typical behaviour of
`declare/local`.

2. Because of this, there is no way to *read* a global var if a calling
scope declares a shadowing var, short of unsetting that shadow var.

3. This is NOTABUG.

Have I got that right? If so, can I suggest a documentation enhancement for
`declare`, from:

The `-g` option forces variables to be created or modified at the global
scope, even when `declare` is executed in a shell function.

to:

The `-g` option forces variables to be created or modified at the global
scope, even when `declare` is executed in a shell function, *and no
references to these variables are created in that function's scope*.


Thanks again!

On Mon, Mar 11, 2024 at 12:08 PM Kerin Millar <kfm@plushkava.net> wrote:

> On Sun, 10 Mar 2024 16:01:10 -0400
> Lawrence Velázquez <vq@larryv.me> wrote:
>
> > On Sun, Mar 10, 2024, at 1:51 PM, Kerin Millar wrote:
> > > Dynamic scoping can be tremendously confusing. The following examples
> > > should help to clarify the present state of affairs.
> > >
> > > $ x() { local a; y; echo "outer: $a"; }
> > > $ y() { local a; a=123; echo "inner: $a"; }
> > > $ x; echo "outermost: $a"
> > > inner: 123
> > > outer:
> > > outermost:
> > >
> > > This is likely as you would expect.
> > >
> > > $ y() { local -g a; a=123; echo "inner: $a"; }
> > > $ x; echo "outermost: $a"
> > > inner: 123
> > > outer: 123
> > > outermost:
> > >
> > > This may not be. There, the effect of the -g option effectively ends
> at
> > > the outermost scope in which the variable, a, was declared. Namely,
> > > that of the x function.
> >
> > This doesn't seem to be accurate; the assignment is performed at
> > the *innermost* declared scope (other than the "local -g" one):
> >
> >       $ x() { local a; y; echo "outer: $a"; }
> >       $ y() { local a; z; echo "inner: $a"; }
> >       $ z() { local -g a; a=123; echo "innermost: $a"; }
> >       $ x; echo "outermost: $a"
> >       innermost: 123
> >       inner: 123
> >       outer:
> >       outermost:
> >
> > Basically, without an assignment, "local -g" does nothing.
>
> It might be tempting to think that the criteria for being "ignored" are
> fulfilled but it is not the case. Below is something that I should also
> have tried before initially posting in this thread.
>
> $ z() { a=123; echo "innermost: $a"; }; unset -v a; x; declare -p a
> innermost: 123
> inner: 123
> outer:
> bash: declare: a: not found
>
> $ z() { local -g a; a=123; echo "innermost: $a"; }; unset -v a; x; declare
> -p a
> innermost: 123
> inner: 123
> outer:
> declare -- a
>
> $ z() { local -g a=456; a=123; echo "innermost: $a"; }; unset -v a; x;
> declare -p a
> innermost: 123
> inner: 123
> outer:
> declare -- a="456"
>
> I think that Greg has it right. The use of the -g option, alone, is
> sufficient to reach into the global scope, though dynamic scoping behaviour
> otherwise remains in effect. That is, one would otherwise still need to pop
> scopes - so to speak - to reach the outermost/bottommost scope.
>
> Speaking of which, to do both of these things has some interesting effects
> ...
>
> $ z() { local -g a; unset -v a; a=123; echo "innermost: $a"; }; unset -v
> a; x; declare -p a
> innermost: 123
> inner: 123
> outer: 123
> declare -- a
>
> $ z() { local -g a; unset -v a; unset -v a; a=123; echo "innermost: $a";
> }; unset -v a; x; declare -p a
> innermost: 123
> inner: 123
> outer: 123
> declare -- a="123"
>
> $ x() { local a; y; local +g a; a=456; echo "outer: $a"; }; unset -v a; x;
> declare -p a
> innermost: 123
> inner: 123
> outer: 456
> declare -- a="123"
>
> I remain somewhat uncertain that the manual conveys enough information to
> be able to perfectly reason with all of this.
>
> --
> Kerin Millar
>


-- 
Regards,
Adrian


reply via email to

[Prev in Thread] Current Thread [Next in Thread]