5

I've been trying to grok lexical scoping (I'm far from convinced by the use of the word lexical but that's another discussion) and I've looked at Wikipedia's entry.

According to the fairly simple Bash script example

$ x=1 
$ function g () { echo $x ; x=2 ; }
$ function f () { local x=3 ; g ; }
$ f # does this print 1, or 3?
3
$ echo $x # does this print 1, or 2?
1

the output from the Bash script is 3, 1. However, it seems to me that it ought to be 3, 2 because the function g prints the (dynamic) value of x and then sets the value of x = 2.

Do I need to correct the Wikipedia entry, or adjust my understanding?

Edwardo
  • 872
  • 1
  • 11
  • 24

3 Answers3

3

Bash vars use the dynamic scoping just as in the wiki page you mentioned.

Examples of languages that use dynamic scoping include Logo, Emacs Lisp, and the shell languages bash, dash, and PowerShell.

Dynamic scoping is fairly easy to implement. To find an identifier's value, the program could traverse the runtime stack, checking each activation record (each function's stack frame) for a value for the identifier.

Bash's own manual says this:

The shell uses dynamic scoping to control a variable's visibility within functions. With dynamic scoping, visible variables and their values are a result of the sequence of function calls that caused execution to reach the current function. The value of a variable that a function sees depends on its value within its caller, if any, whether that caller is the "global" scope or another shell function. This is also the value that a local variable declaration "shadows", and the value that is restored when the function returns.

For example, if a variable var is declared as local in function func1, and func1 calls another function func2, references to var made from within func2 will resolve to the local variable var from func1, shadowing any global variable named var.

For how this can be used see Bash: Passing variables by reference.

pynexj
  • 19,215
  • 5
  • 38
  • 56
1

From the bash man page description of the local built-in (emphasis mine)

When local is used within a function, it causes the variable name to have a visible scope restricted to that function and its children.

When g is called, the value of x (not being marked local) is used from the closest enclosing runtime context. When g is called from f, that means the local variable x defined by f, not the global variable x. This applies both to the lookup and assignments to x. When g is called from the global scope, x refers to the global variable x.

This contrasts with lexical scoping, in which the x in the function g would always refer to global x, because g is defined in the global scope. Where a function is called from isn't relevant.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • Sorry for bothering you. I hope it's ok to ask. :) I'm sitting in front of a shell program which hardly uses dynamic scoping, mainly to pass arrays between functions. Variables are used in different functions and combination of functions and those functions are spread across five source files. In my opinion this code is less readable/followable and the fact that functions are tightly coupled makes it prone to bugs and hard to maintain. Would you say that this is just normal practice for shell code and I have to expect that or do you agree? – hek2mgl Sep 27 '18 at 21:31
0

g assigns 2 to the local x of the function f. When f ends, his activation record is popped from the stack, then the second echo looks up in the stack and finds the x = 1 of the beginning.

Kim
  • 4,080
  • 2
  • 30
  • 51