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: Kerin Millar
Subject: Re: "local -g" declaration references local var in enclosing scope
Date: Mon, 11 Mar 2024 04:08:02 +0000

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



reply via email to

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