My Pages

Wednesday, November 24, 2010

Dynamic versus Static Scoping

Dynamic and static scoping both have specific places in programming. We're going to discuss what the difference is and why the differences can make a difference in your program.

What is scoping
When we are talking about scoping, we are mainly concerned about the bindings of variables. In other words, where they have been defined. In some languages such as Perl there is no actual need to define a variable but that is a discussion for a different day. Regardless, bindings of variables show that they are variables and of what type they are. Below you can see the bindings of the variable x and variable y as being an integer and float respectively.

int x;
float y;

x = 10;
y = 3.14;


When we begin talking about scoping, we are specifically talking about scoping within higher order functions, closures, and Lambda Functions. Why? Because this is where scoping really matters within the variables. For example, in a language such as C, there is no purpose to talk about static versus dynamic scoping because everything is static. It will make more sense once we begin talking about it. Essentially variable bindings decide what variable a specific variable is talking about. For example, we KNOW that x is referring to int x.

Static Scoping
This is the scoping style that most people are used to and is the standard. So let's look at an explanation; essentially, the variable that is free (so during a closure or higher order function) is bound to the closest variable when the function is defined. An example is shown below.

var x=20;
var newfunc = f();
newfunc();

function f() {
  var x = 10;
  return function s() { print x; };
}


So, what prints out? You may or may not be surprised to find out that "10" will be printed out. Why? Because the x that is bound is the x from within f(); this is because the variable is bound statically and usually at compile time.

Dynamic Scoping
This is the scoping style that most people are not used to and can sometimes provide really strange results during programming. So let's look at an explanation; essentially, the variable that is free (so during a closure or higher order function) is bound to the closest variable in the activation records during run time. So what does this mean? The variable is bound to whatever the closest variable name is when the function is executed.

function d() {
  var x=20;
  var newfunc = f();
  newfunc();
}

var x=30;
d();

function f() {
  var x = 10;
  return function s() { print x; };
}


In the example shown above, one may be surprised to see that the output would be "20"; but why? the reason is quite surprising. The x is a free variable that must be bound at runtime; so when we actually execute newfunc() we look back through the activation records until we find a variable x that can be used. So we look at the AR for newfunc but find no x. We then check the AR for d and find that there is a local variable x defined as 20. This becomes the binding for our x. Now below you can see one more example of this.

function d() {
  var newfunc = f();
  newfunc();
}

function n() {
  var x=30;
  d();
}

n();

function f() {
  var x = 10;
  return function s() { print x; };
}


In this instance, the output changes again; now we see "30" as the output. Why? Let's step through it. We execute newfunc() and we see the free variable x that we need to bind. We then check the AR of newfunc but find no definition of x. We then look in the AR of d. Again, we see no definition of x so we continue up the AR's to n's definition. Here we now find an x which we then use which was defined as "30."

Let's get an example of both in Perl; static scoping is done via the my operator and the local operator provides dynamic scoping. Please note that by using the local operator, "use strict" will cause an error with using the variable and will say that the variable is not declared. Let's look at both examples.

Static
The output is "10", again, notice that the $x is bound to 10 from when the Lambda function is created.

sub f() {
  my $x = 10;
  return sub { print $x . "\n"; };
}

my $func = f();
my $x = 20;
&{$func}();


Dynamic
The output is "20", again, notice that the $x is bound to 20 from when the Lambda function is actually executed.

sub f() {
  local $x = 10;
  return sub { print $x . "\n"; };
}

my $func = f();
local $x = 20;
&{$func}();


Why is this useful?
Well... Let's be honest, essentially it's like passing a variable to a function. However, you could set it up so that you could dynamically change a function's internal variable if all variables were free dynamically scoped variables. This would allow for other functions to change the meanings of the functions without having to pass all the variables in. In my experience this is really not that useful. But knowing what the difference is and knowing how to tell which mode a variable is assigned to (in languages like Lisp and Perl that support both) is important. Or if you end up having to maintain a piece of code that uses dynamic scoping, you will know what exactly it means and the side effects of them.

No comments: