// start pseudo-code
var y = "global";
function print-y() {
print(y);
}
function test-scope() {
var y = "local";
print-y();
}
test-scope(); // statically scoped languages print "global"
// dynamically languages print "local"
print-y(); // all languages should print "global"
// end pseudo-code
This is the standard type of example used to explain what static scoping is as compared to dynamic scoping. This makes sense to me, but never really sank in.
To anyone who already gets this, this will seem trivial. But the lightbulb went off for me when I thought about static vs dynamic typing…
In a dynamically typed language (like ruby, javascript, etc), types are not checked until execution. If an expression evaluates, then the type-checking worked. If not, it blows up to your error handling or the user. Statically typed languages check types at compile time. The programmer ensures that parameter types are specified and the compiler ensures the programmers wishes will be followed.
Thinking in this fashion, static/dynamic scoping makes sense. For the following explanation, pretend that variables only have one type of storage for simplicity, and that global y is at memory location x01, while local y in test-scope is at x02.
If I’m a compiler in the act of compiling print-y (above code snippet) in a static language, then I know the scope I’m running in (hence static scope). I know that y is bound to the global variable, and I can replace that y with a direct location of x01 in the assembly I’m generating. No lookup tables, etc… fast.
If instead, I’m compling print-y in a dynamic scope, then I can make no such substitution. I’m going to make some calls to print-y that will point to x01 and others that point to x02. What y is bound to is determined by the scope of the call at runtime… which is the definition of dynamic scoping.
So that might help it click. Everything said about a stack in dynamic scoping is true, but I think it’s easier to understand that once you understand the above. Then you realize I could nest 4 or 5 of those calls and the last value of y would win.
So to sum up…
Static Scoping – Variables can be bound at compile time without regards to calling code.
Dynamic Scoping – Variable binding (context) can only be determined at the moment code is executed.
Emacs Lisp (elisp) is one of the few commonly used languages with dynamic scoping. It takes a lot of heat for that, as debugging and understanding the nuances involved place a greater burden on the developer. But I think it’s worth noting that in order to create an extensible system that can completely modify itself at runtime (via loading/reloading custom code) and allow extensions to modify extensions… the combination of a dynamic language and dynamic scoping has proved very successful.
If you’re interested in learning more about languages, I recommend checking out Programming Language Pragmatics, Third Edition, as well as Steve Yegge’s blog posts.
Comments
13 responses to “Static vs Dynamic Scope”
print-y() is supposed to print y not x
thanks, fixed
Hi.
Dynamic scope is very powerful feature, and it is, in my opinion, right choice for languages like Lisp. For example, if
(my-macro expr1 … exprn)
is macro call in Lisp, then there is a my-function, such that expression above is equivalent to
(my-function ‘expr1 … ‘exprn),
and furthermore, my-function is the first class value. So, if looked from purely expressive power point of view,
dynamic scope + functions
is simpler and more expressive combination than
lexical scope + functions + macros.
That is well kept secret of Lispers, who want to make impression that macros are something exceptional. Advantage of lexical scope is primarily in speed; it is easier to “compile away” variables. Just like you explained. Another issue frequently mentioned is safety. Its easier to shoot one into his foot. But, it is not big issue once one have some experience.
Thank you for this post. I super-liked it.
don’t know why linked-in is a tag,though 🙂
@Bhoot, Thanks. As for the linked-in tag, having it there auto-posts it to my linked-in account. It doesn’t mean the post is about linked in. Sorry for any confusion.
The problem with dynamic scoping is that the function print-y() must rely on the fact that y has been set appropriately by one of its callers.
If we had the following snippet:
var y = new G();
function foo() {
y.bar();
}
function foo-caller() {
var y = new L();
foo();
}
and if type L provides a method bar() that is not provided by type G, then foo() would only work if it is invoked by foo-caller(). If it were invoked in a state where y has type G it would fail.
In other words: with dynamic scoping the functions are more closely coupled. If the same function is called by different callers it might work or not depending on the caller.
@Peter,
The problem you mention is more an issue of dynamic typing than dynamic scope.
I could just as easily use a param in a lexically scoped language in a dynamically typed language and have the same problem.
thanks 4 this post,I used it:)
thanks…
thanx it ll most useful 4 me
thnx now i understand
thanx now i undestand
thanx neh….