Blog in monospace

Scoping in modern programming languages

Warning: this is a more advanced post I assume you know certain things about programming languages

A few weeks ago I learnt about a concept called “scoping” in programming languages.

At its core it actually is only about which variables are available where. Let’s take a little example in Javascript:

    function test(a,b) {
            return a+b+c;
    }   

    test(1,2)

This will obviously fail because c is never defined anywhere.

But what if we do this:

    function helper(a,b,c) {
            return test(a,b)
    }

    function test(a,b){
            return a+b+c;
    }

    helper(1,2,3)

Will this work?

You might say “ofcourse not because c is only available to the helper function not the test function” and your are correct.

However this is not the case in all programming languages. Actually we have two types of scoping:

The first one is the one used in this example, statical or lexical scoping means that the function has only access to the variables and functions in the context where the function was defined.

If we had put a variable declaration in the global context our code would’ve worked.

Ex:

    // This is the global context

    // global variable
    var c = 3

    function helper(a,b,c) {
            // A function has its own context
            // This function has access to variables a, b and c and global variables defined outside of it
            return test(a,b)
    }

    function test(a,b){
            return a+b+c;
    }

Link to JSfiddle, please go verify yourself, don’t blindly believe me

This is because c is now defined where we defined our function so it has access to this “c”.

Dynamic scoping on the other hand takes a different approach. In this case functions have access to the variables and other functions in the context (or place) where they were called.

If Javascript would have been dynamically scoped our first code would have worked.

Now let’s take a look at what the other programming languages are doing.

Python

    def helper(a,b,c):
        return test(a,b)

    def test(a,b):
        return a+b+c

    print(helper(1,2,4))

Running this will throw an “global name c is undefined” error in both python3 als python2.7.

This means Python is a lexical or statically scoped language.

Introducing another global variable called “c” helps to solve the error:

    def helper(a,b,c):
        return test(a,b)

    def test(a,b):
        return a+b+c

    print(helper(1,2,4))

Ruby

    def test(a,b)
            return a+b+c
    end

    def helper(a,b,c)
            return test(a,b)
    end

Again Ruby will complain about this but it will throw a different error:

    undefined local variable or method

So Ruby knows that “c” must be a local variable, meaning that c should be defined in the method “test”.

Okay, let’s try our previous solution and see if it works:

    c = 3

    def test(a,b)
            return a+b+c
    end

    def helper(a,b,c)
            return test(a,b)
    end

    helper(1,2,3)

    $ ruby scoping.rb
    scoping.rb:4:in `test': undefined local variable or method `c' for main:Object (NameError)
        from scoping.rb:8:in `helper'
        from scoping.rb:11:in `<main>'

Huh? Ruby throws the same error as before?

This is because Ruby makes a difference between local, instance and global variables, but I will talk about that in another post.

For now we can solve it by appending an “@” to “c”

    @c = 3

    def test(a,b)
            return a+b+@c
    end

    def helper(a,b,c)
            return test(a,b)
    end

    helper(1,2,3)

The “@” tells ruby not to look only in its own local context (the context of the method “test”) but also outside it for a variable named “c”, if we don’t append the “@” before c Ruby can’t know if you mean a variable inside “test” or outside it.

Summary

Pheh that is done.

I know these things can be quite complex and abstract, certainly if you don’t know the language well.

But in summary this is what we did:

You won’t find a lot of languages that are dynamically scoped, this is because the code could behave differently than you would expect and you would need to carefully analyse your code in order to know what it would do because your variables could just change everywhere in your code.

Thanks for reading!

Written by Bram Vandenbogaerde