742

What is a brief introduction to lexical scoping?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Subba Rao
  • 9,518
  • 7
  • 26
  • 31
  • 94
    In podcast 58, Joel encourages questions likes these as he wants SO to become THE place for answers, even if they have been answered in other places. This is a valid question, even though one could put it a little more polite. – Ralph M. Rickenbach Jun 26 '09 at 05:30
  • And then specially http://en.wikipedia.org/wiki/Scope_(programming) which has a nice (Pascal/Delphi) example of nested scopes in nested procedures. – Marco van de Voort Jun 26 '09 at 22:35
  • 7
    @rahul I understand it's an old question. But I am sure even in 2009, SO expected the askers to put in *some basic effort* towards solving it. As it stands it doesn't show *any* effort at all. May be, that's why it was downvoted by many? – P.P Sep 12 '13 at 12:05
  • 14
    It's possible that the asker is not (or was not) fluent in English when writing this question – Martin Jan 16 '14 at 19:24
  • 33
    The question is polite, he just say what he wants. You are free to answer. No need for oversensible politness here. – Markus Siebeneicher Apr 24 '14 at 11:08
  • 30
    I think questions like these are great because it builds content for SO. IMO, who cares if the question doesn't have effort... the answers will have great content and that's what matters on this message board. – Jwan622 Oct 04 '14 at 22:42
  • 6
    i garee with @Jwan622 a question does not need to be verbose to be a good question. – Andrew Dec 10 '15 at 00:38

18 Answers18

730

I understand them through examples. :)

First, lexical scope (also called static scope), in C-like syntax:

void fun()
{
    int x = 5;

    void fun2()
    {
        printf("%d", x);
    }
}

Every inner level can access its outer levels.

There is another way, called dynamic scope used by the first implementation of Lisp, again in a C-like syntax:

void fun()
{
    printf("%d", x);
}

void dummy1()
{
    int x = 5;

    fun();
}

void dummy2()
{
    int x = 10;

    fun();
}

Here fun can either access x in dummy1 or dummy2, or any x in any function that call fun with x declared in it.

dummy1();

will print 5,

dummy2();

will print 10.

The first one is called static because it can be deduced at compile-time, and the second is called dynamic because the outer scope is dynamic and depends on the chain call of the functions.

I find static scoping easier for the eye. Most languages went this way eventually, even Lisp (can do both, right?). Dynamic scoping is like passing references of all variables to the called function.

As an example of why the compiler can not deduce the outer dynamic scope of a function, consider our last example. If we write something like this:

if(/* some condition */)
    dummy1();
else
    dummy2();

The call chain depends on a run time condition. If it is true, then the call chain looks like:

dummy1 --> fun()

If the condition is false:

dummy2 --> fun()

The outer scope of fun in both cases is the caller plus the caller of the caller and so on.

Just to mention that the C language does not allow nested functions nor dynamic scoping.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
AraK
  • 87,541
  • 35
  • 171
  • 230
  • 19
    I would also like to point out a very very easy to understand tutorial I just found. Arak's example is nice, but may be too short for someone who needs more examples (actually, comparing with other languages..). Take a look. It is important to understand *this*, as that keyword will lead us to understand lexical scope. http://howtonode.org/what-is-this – CppLearner Aug 08 '11 at 06:13
  • It's good to note that gcc has an extension allowing nested functions. – Corey Richardson Sep 13 '13 at 03:50
  • 14
    This is a good answer. But the question is tagged with `JavaScript`. Therefore I think this shouldn't be marked as the accepted answer. Lexical scope specifically in JS is different – Boyang Oct 01 '16 at 10:29
  • 6
    Extremely good answer. Thank you. @Boyang I disagree. I'm not a Lisp coder, but found the Lisp example helpful, since it's an example of dynamic scoping, which you don't get in JS. – dudewad Oct 10 '16 at 20:36
  • 5
    Initially I thought the example was valid C code and was confused whether there was dynamic scoping in C. Perhaps the disclaimer at the end could be shifted to before the code example? – Yangshun Tay Apr 08 '17 at 07:28
  • 2
    This is still a very helpful answer but I think @Boyang is correct. This answer refers to 'level', which is more along the lines of block scope that C has. JavaScript by default does not have block level scope, so inside a `for` loop is the typical problem. Lexical scope for JavaScript is only at the function level unless the ES6 `let` or `const` is used. – icc97 Apr 19 '18 at 11:44
  • The best way to answer the question is to compare it with other types of scopes. I wish more answers would follow the same approach! – Mikhail Kalashnikov Jun 02 '18 at 00:56
  • i want to make sure if the phrase `because it can be deduced at compile-time` is correct or not? because from what i have understood, scoping is done for memory allocation of non local data ( `int x` in your case, in example for lexical scope) and since memory allocation for local data is handled by Activation Records( and therefore stack memory) at **runtime** , i presumed that for non local data, scoping would be done in heap memory at **runtime too** . if my presumption is correct, Does a language supporting block structure or not completely changes memory allocation schemes? – ansh sachdeva Apr 25 '19 at 23:12
  • It's true that in these examples the compiler cannot know the possible outer dynamic scope of the function `fun()` when it *defined*, but it is not correct that the "compiler can not deduce the outer dynamic scope" for the `if` statement example. The answer itself is able to deduce the scope for each side of the conditional separately, so why could the compiler not do that? The given examples are finite and completely deterministic and the state of any variable `x` is not changed by the function(s). The non-deterministic result of a conditional statement is separate from dynamic scoping. – C Perkins Jun 14 '19 at 22:34
322

Lets try the shortest possible definition:

Lexical Scoping defines how variable names are resolved in nested functions: inner functions contain the scope of parent functions even if the parent function has returned.

That is all there is to it!

Pierre Spring
  • 9,501
  • 13
  • 44
  • 43
72
var scope = "I am global";
function whatismyscope(){
   var scope = "I am just a local";
   function func() {return scope;}
   return func;
}

whatismyscope()()

The above code will return "I am just a local". It will not return "I am a global". Because the function func() counts where is was originally defined which is under the scope of function whatismyscope.

It will not bother from whatever it is being called(the global scope/from within another function even), that's why global scope value I am global will not be printed.

This is called lexical scoping where "functions are executed using the scope chain that was in effect when they were defined" - according to JavaScript Definition Guide.

Lexical scope is a very very powerful concept.

Hope this helps..:)

rayryeng
  • 96,704
  • 21
  • 166
  • 177
kta
  • 17,024
  • 7
  • 58
  • 43
  • 5
    it very nice explanation i want to add one more thing if you write function func() {return this.scope;} then it will return "I am global" just use this keyword and your scope will get change – Rajesh Kumar Bhawsar Sep 11 '19 at 03:01
46

Lexical (AKA static) scoping refers to determining a variable's scope based solely on its position within the textual corpus of code. A variable always refers to its top-level environment. It's good to understand it in relation to dynamic scope.

Evan Meagher
  • 4,237
  • 19
  • 17
43

Scope defines the area, where functions, variables and such are available. The availability of a variable for example is defined within its the context, let's say the function, file, or object, they are defined in. We usually call these local variables.

The lexical part means that you can derive the scope from reading the source code.

Lexical scope is also known as static scope.

Dynamic scope defines global variables that can be called or referenced from anywhere after being defined. Sometimes they are called global variables, even though global variables in most programmin languages are of lexical scope. This means, it can be derived from reading the code that the variable is available in this context. Maybe one has to follow a uses or includes clause to find the instatiation or definition, but the code/compiler knows about the variable in this place.

In dynamic scoping, by contrast, you search in the local function first, then you search in the function that called the local function, then you search in the function that called that function, and so on, up the call stack. "Dynamic" refers to change, in that the call stack can be different every time a given function is called, and so the function might hit different variables depending on where it is called from. (see here)

To see an interesting example for dynamic scope see here.

For further details see here and here.

Some examples in Delphi/Object Pascal

Delphi has lexical scope.

unit Main;
uses aUnit;  // makes available all variables in interface section of aUnit

interface

  var aGlobal: string; // global in the scope of all units that use Main;
  type 
    TmyClass = class
      strict private aPrivateVar: Integer; // only known by objects of this class type
                                    // lexical: within class definition, 
                                    // reserved word private   
      public aPublicVar: double;    // known to everyboday that has access to a 
                                    // object of this class type
    end;

implementation

  var aLocalGlobal: string; // known to all functions following 
                            // the definition in this unit    

end.

The closest Delphi gets to dynamic scope is the RegisterClass()/GetClass() function pair. For its use see here.

Let's say that the time RegisterClass([TmyClass]) is called to register a certain class cannot be predicted by reading the code (it gets called in a button click method called by the user), code calling GetClass('TmyClass') will get a result or not. The call to RegisterClass() does not have to be in the lexical scope of the unit using GetClass();

Another possibility for dynamic scope are anonymous methods (closures) in Delphi 2009, as they know the variables of their calling function. It does not follow the calling path from there recursively and therefore is not fully dynamic.

Community
  • 1
  • 1
Ralph M. Rickenbach
  • 12,121
  • 5
  • 25
  • 47
  • 2
    Actually private is accessable in the whole unit where the class is defined. This is why "Strict private" was introduced in D2006. – Marco van de Voort Jun 26 '09 at 22:34
  • 2
    +1 for plain language (as opposed to both complicated language and examples without much description) – Pops Apr 27 '10 at 17:48
37

I love the fully featured, language-agnostic answers from folks like @Arak. Since this question was tagged JavaScript though, I'd like to chip in some notes very specific to this language.

In JavaScript our choices for scoping are:

  • as-is (no scope adjustment)
  • lexical var _this = this; function callback(){ console.log(_this); }
  • bound callback.bind(this)

It's worth noting, I think, that JavaScript doesn't really have dynamic scoping. .bind adjusts the this keyword, and that's close, but not technically the same.

Here is an example demonstrating both approaches. You do this every time you make a decision about how to scope callbacks so this applies to promises, event handlers, and more.

Lexical

Here is what you might term Lexical Scoping of callbacks in JavaScript:

var downloadManager = {
  initialize: function() {
    var _this = this; // Set up `_this` for lexical access
    $('.downloadLink').on('click', function () {
      _this.startDownload();
    });
  },
  startDownload: function(){
    this.thinking = true;
    // Request the file from the server and bind more callbacks for when it returns success or failure
  }
  //...
};

Bound

Another way to scope is to use Function.prototype.bind:

var downloadManager = {
  initialize: function() {
    $('.downloadLink').on('click', function () {
      this.startDownload();
    }.bind(this)); // Create a function object bound to `this`
  }
//...

These methods are, as far as I know, behaviorally equivalent.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
SimplGy
  • 18,875
  • 14
  • 95
  • 138
17

Lexical scope means that in a nested group of functions, the inner functions have access to the variables and other resources of their parent scope.

This means that the child's functions are lexically bound to the execution context of their parents.

Lexical scope is sometimes also referred to as static scope.

function grandfather() {
    var name = 'Hammad';
    // 'likes' is not accessible here
    function parent() {
        // 'name' is accessible here
        // 'likes' is not accessible here
        function child() {
            // Innermost level of the scope chain
            // 'name' is also accessible here
            var likes = 'Coding';
        }
    }
}

The thing you will notice about lexical scope is that it works forward, meaning the name can be accessed by its children's execution contexts.

But it doesn't work backward to its parents, meaning that the variable likes cannot be accessed by its parents.

This also tells us that variables having the same name in different execution contexts gain precedence from top to bottom of the execution stack.

A variable, having a name similar to another variable, in the innermost function (topmost context of the execution stack) will have higher precedence.

Source.

AConsumer
  • 1,414
  • 1
  • 10
  • 24
16

A lexical scope in JavaScript means that a variable defined outside a function can be accessible inside another function defined after the variable declaration. But the opposite is not true; the variables defined inside a function will not be accessible outside that function.

This concept is heavily used in closures in JavaScript.

Let's say we have the below code.

var x = 2;
var add = function() {
    var y = 1;
    return x + y;
};

Now, when you call add() --> this will print 3.

So, the add() function is accessing the global variable x which is defined before method function add. This is called due to lexical scoping in JavaScript.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Praveen Kishor
  • 1,713
  • 1
  • 18
  • 19
  • Consider that the code snippet was for a dynamically-scoped language. If the `add()` function where called immediately following the given code snippet, it would also print 3. Lexical scoping does not simply mean that a function can access global variables outside the local context. So the example code really doesn't help to show what lexical scoping means. Showing lexical scoping in code really needs a counter example or at least an explanation of other possible interpretations of the code. – C Perkins Jun 14 '19 at 22:44
15

In simple language, lexical scope is a variable defined outside your scope or upper scope is automatically available inside your scope which means you don't need to pass it there.

Example:

let str="JavaScript";

const myFun = () => {
    console.log(str);
}

myFun();

// Output: JavaScript

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
J.K.A.
  • 6,566
  • 23
  • 88
  • 151
  • 2
    The shortest and the best answer for me with an example. Could have been added that the ES6' arrow functions solve the problem with `bind`. With them, the `bind` is no longer required. For more information about this change check https://stackoverflow.com/a/34361380/11127383 – Daniel Danielecki Jan 20 '20 at 14:37
12

IBM defines it as:

The portion of a program or segment unit in which a declaration applies. An identifier declared in a routine is known within that routine and within all nested routines. If a nested routine declares an item with the same name, the outer item is not available in the nested routine.

Example 1:

function x() {
    /*
    Variable 'a' is only available to function 'x' and function 'y'.
    In other words the area defined by 'x' is the lexical scope of
    variable 'a'
    */
    var a = "I am a";

    function y() {
        console.log( a )
    }
    y();

}
// outputs 'I am a'
x();

Example 2:

function x() {

    var a = "I am a";

    function y() {
         /*
         If a nested routine declares an item with the same name,
         the outer item is not available in the nested routine.
         */
        var a = 'I am inner a';
        console.log( a )
    }
    y();

}
// outputs 'I am inner a'
x();
Robert Rocha
  • 8,656
  • 15
  • 59
  • 110
12

Lexical scoping: Variables declared outside of a function are global variables and are visible everywhere in a JavaScript program. Variables declared inside a function have function scope and are visible only to code that appears inside that function.

Stan
  • 129
  • 1
  • 2
7

Lexical scope means that a function looks up variables in the context where it was defined, and not in the scope immediately around it.

Look at how lexical scope works in Lisp if you want more detail. The selected answer by Kyle Cronin in Dynamic and Lexical variables in Common Lisp is a lot clearer than the answers here.

Coincidentally I only learned about this in a Lisp class, and it happens to apply in JavaScript as well.

I ran this code in Chrome's console.

// JavaScript               Equivalent Lisp
var x = 5;                //(setf x 5)
console.debug(x);         //(print x)
function print_x(){       //(defun print-x ()
    console.debug(x);     //    (print x)
}                         //)
(function(){              //(let
    var x = 10;           //    ((x 10))
    console.debug(x);     //    (print x)
    print_x();            //    (print-x)
})();                     //)

Output:

5
10
5
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
ratiotile
  • 705
  • 5
  • 15
4

There is an important part of the conversation surrounding lexical and dynamic scoping that is missing: a plain explanation of the lifetime of the scoped variable - or when the variable can be accessed.

Dynamic scoping only very loosely corresponds to "global" scoping in the way that we traditionally think about it (the reason I bring up the comparison between the two is that it has already been mentioned - and I don't particularly like the linked article's explanation); it is probably best we don't make the comparison between global and dynamic - though supposedly, according to the linked article, "...[it] is useful as a substitute for globally scoped variables."

So, in plain English, what's the important distinction between the two scoping mechanisms?

Lexical scoping has been defined very well throughout the answers above: lexically scoped variables are available - or, accessible - at the local level of the function in which it was defined.

However - as it is not the focus of the OP - dynamic scoping has not received a great deal of attention and the attention it has received means it probably needs a bit more (that's not a criticism of other answers, but rather a "oh, that answer made we wish there was a bit more"). So, here's a little bit more:

Dynamic scoping means that a variable is accessible to the larger program during the lifetime of the function call - or, while the function is executing. Really, Wikipedia actually does a nice job with the explanation of the difference between the two. So as not to obfuscate it, here is the text that describes dynamic scoping:

...[I]n dynamic scoping (or dynamic scope), if a variable name's scope is a certain function, then its scope is the time-period during which the function is executing: while the function is running, the variable name exists, and is bound to its variable, but after the function returns, the variable name does not exist.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Thomas
  • 4,827
  • 5
  • 28
  • 60
4

Lexical scope refers to the lexicon of identifiers (e.g., variables, functions, etc.) visible from the current position in the execution stack.

- global execution context
    - foo
    - bar
    - function1 execution context
        - foo2
        - bar2
        - function2 execution context
            - foo3
            - bar3

foo and bar are always within the lexicon of available identifiers because they are global.

When function1 is executed, it has access to a lexicon of foo2, bar2, foo, and bar.

When function2 is executed, it has access to a lexicon of foo3, bar3, foo2, bar2, foo, and bar.

The reason global and/or outer functions do not have access to an inner functions identifiers is because the execution of that function has not occurred yet and therefore, none of its identifiers have been allocated to memory. What’s more, once that inner context executes, it is removed from the execution stack, meaning that all of it’s identifiers have been garbage collected and are no longer available.

Finally, this is why a nested execution context can ALWAYS access it’s ancestors execution context and thus why it has access to a greater lexicon of identifiers.

See:

Special thanks to @robr3rd for help simplifying the above definition.

Kenneth Stoddard
  • 1,179
  • 8
  • 12
2

Here's a different angle on this question that we can get by taking a step back and looking at the role of scoping in the larger framework of interpretation (running a program). In other words, imagine that you were building an interpreter (or compiler) for a language and were responsible for computing the output, given a program and some input to it.

Interpretation involves keeping track of three things:

  1. State - namely, variables and referenced memory locations on the heap and stack.

  2. Operations on that state - namely, every line of code in your program

  3. The environment in which a given operation runs - namely, the projection of state on an operation.

An interpreter starts at the first line of code in a program, computes its environment, runs the line in that environment and captures its effect on the program's state. It then follows the program's control flow to execute the next line of code, and repeats the process till the program ends.

The way you compute the environment for any operation is through a formal set of rules defined by the programming language. The term "binding" is frequently used to describe the mapping of the overall state of the program to a value in the environment. Note that by "overall state" we do not mean global state, but rather the sum total of every reachable definition, at any point in the execution).

This is the framework in which the scoping problem is defined. Now to the next part of what our options are.

  • As the implementor of the interpreter, you could simplify your task by making the environment as close as possible to the program's state. Accordingly, the environment of a line of code would simply be defined by environment of the previous line of code with the effects of that operation applied to it, regardless of whether the previous line was an assignment, a function call, return from a function, or a control structure such as a while loop.

This is the gist of dynamic scoping, wherein the environment that any code runs in is bound to the state of the program as defined by its execution context.

  • Or, you could think of a programmer using your language and simplify his or her task of keeping track of the values a variable can take. There are way too many paths and too much complexity involved in reasoning about the outcome the totality of past execution. Lexical Scoping helps do this by restricting the current environment to the portion of state defined in the current block, function or other unit of scope, and its parent (i.e. the block enclosing the current clock, or the function that called the present function).

In other words, with lexical scope the environment that any code sees is bound to state associated with a scope defined explicitly in the language, such as a block or a function.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
er0
  • 1,445
  • 1
  • 11
  • 27
1

Ancient question, but here is my take on it.

Lexical (static) scope refers to the scope of a variable in the source code.

In a language like JavaScript, where functions can be passed around and attached and re-attached to miscellaneous objects, you might have though that scope would depend on who’s calling the function at the time, but it doesn’t. Changing the scope that way would be dynamic scope, and JavaScript doesn’t do that, except possibly with the this object reference.

To illustrate the point:

var a='apple';

function doit() {
    var a='aardvark';
    return function() {
        alert(a);
    }
}

var test=doit();
test();

In the example, the variable a is defined globally, but shadowed in the doit() function. This function returns another function which, as you see, relies on the a variable outside of its own scope.

If you run this, you will find that the value used is aardvark, not apple which, though it is in the scope of the test() function, is not in the lexical scope of the original function. That is, the scope used is the scope as it appears in the source code, not the scope where the function is actually used.

This fact can have annoying consequences. For example, you might decide that it’s easier to organise your functions separately, and then use them when the time comes, such as in an event handler:

var a='apple',b='banana';

function init() {
  var a='aardvark',b='bandicoot';
  document.querySelector('button#a').onclick=function(event) {
    alert(a);
  }
  document.querySelector('button#b').onclick=doB;
}

function doB(event) {
  alert(b);
}

init();
<button id="a">A</button>
<button id="b">B</button>

This code sample does one of each. You can see that because of lexical scoping, button A uses the inner variable, while button B doesn’t. You may end up nesting functions more than you would have liked.

By the way, in both examples, you will also notice that the inner lexically scoped variables persist even though the containing function function has run its course. This is called closure, and refers to a nested function’s access to outer variables, even if the outer function has finished. JavaScript needs to be smart enough to determine whether those variables are no longer needed, and if not, can garbage collect them.

Manngo
  • 8,349
  • 6
  • 50
  • 74
-1

I normally learn by example, and here's a little something:

const lives = 0;

function catCircus () {
    this.lives = 1;
    const lives = 2;

    const cat1 = {
        lives: 5,
        jumps: () => {
            console.log(this.lives);
        }
    };
    cat1.jumps(); // 1
    console.log(cat1); // { lives: 5, jumps: [Function: jumps] }

    const cat2 = {
        lives: 5,
        jumps: () => {
            console.log(lives);
        }
    };
    cat2.jumps(); // 2
    console.log(cat2); // { lives: 5, jumps: [Function: jumps] }

    const cat3 = {
        lives: 5,
        jumps: () => {
            const lives = 3;
            console.log(lives);
        }
    };
    cat3.jumps(); // 3
    console.log(cat3); // { lives: 5, jumps: [Function: jumps] }

    const cat4 = {
        lives: 5,
        jumps: function () {
            console.log(lives);
        }
    };
    cat4.jumps(); // 2
    console.log(cat4); // { lives: 5, jumps: [Function: jumps] }

    const cat5 = {
        lives: 5,
        jumps: function () {
            var lives = 4;
            console.log(lives);
        }
    };
    cat5.jumps(); // 4
    console.log(cat5); // { lives: 5, jumps: [Function: jumps] }

    const cat6 = {
        lives: 5,
        jumps: function () {
            console.log(this.lives);
        }
    };
    cat6.jumps(); // 5
    console.log(cat6); // { lives: 5, jumps: [Function: jumps] }

    const cat7 = {
        lives: 5,
        jumps: function thrownOutOfWindow () {
            console.log(this.lives);
        }
    };
    cat7.jumps(); // 5
    console.log(cat7); // { lives: 5, jumps: [Function: thrownOutOfWindow] }
}

catCircus();
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
basickarl
  • 25,903
  • 43
  • 172
  • 270
-1

This topic is strongly related with the built-in bind function and introduced in ECMAScript 6 Arrow Functions. It was really annoying, because for every new "class" (function actually) method we wanted to use, we had to bind this in order to have access to the scope.

JavaScript by default doesn't set its scope of this on functions (it doesn't set the context on this). By default you have to explicitly say which context you want to have.

The arrow functions automatically gets so-called lexical scope (have access to variable's definition in its containing block). When using arrow functions it automatically binds this to the place where the arrow function was defined in the first place, and the context of this arrow functions is its containing block.

See how it works in practice on the simplest examples below.

Before Arrow Functions (no lexical scope by default):

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const globalScope = programming.getLanguage;
console.log(globalScope()); // Output: undefined

const localScope = programming.getLanguage.bind(programming);
console.log(localScope()); // Output: "JavaScript"

With arrow functions (lexical scope by default):

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const arrowFunction = () => {
    console.log(programming.getLanguage());
}

arrowFunction(); // Output: "JavaScript"
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Daniel Danielecki
  • 3,527
  • 3
  • 29
  • 41