On Sun, 10 Mar 2024 16:01:10 -0400 Lawrence Velázquez <v...@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