With dynamic scoping, a callee can access the variables of its caller. Pseudo C code:

void foo()
{
    print(x);
}

void bar()
{
    int x = 42;
    foo();
}

Since I have never programmed in a language that supports dynamic scoping, I wonder what some real world use cases for dynamic scoping would be.

  • maybe it's easier to implement when the interpreter is implemented in some particular other language? – Alf P. Steinbach Aug 23 '11 at 18:19
  • 2
    It's of sufficiently little use that most languages that once used it (e.g., Lisp) don't any more. Just for one obvious example, most early Lisp implementations used dynamic scoping, but now all the major variants (e.g., CL, Scheme) use lexical scoping. – Jerry Coffin Aug 23 '11 at 19:20
  • 1
    @JerryCoffin: Notable exceptions include Perl and Emacs Lisp—both used dynamic scoping originally, and now (Perl 5, Emacs 24) have support for both dynamic and lexical scoping. It’s nice to be able to choose. – Jon Purdy Feb 12 '15 at 21:10
  • @JerryCoffin It doesn't exactly match the coded example but javascript still makes wide use of dynamic scoping if I understand the question right. Still trying to think of an general advantage it provides that doesn't merely make up for a short coming of the language though. – Adrian Dec 15 '16 at 9:44
  • @JerryCoffin There's still some dynamic scoping actively used in Common Lisp, mostly around dynamic control of reading and printing. – Vatine Dec 15 '16 at 10:42
up vote 15 down vote accepted

A very useful application of dynamic scoping is for passing contextual parameters without having to add new parameters explicitly to every function in a call stack

For example, Clojure supports dynamic scoping via binding, which can be used to temporarily reassign the value of *out* for printing. If you re-bind *out* then every call to print within the dynamic scope of the binding will print to your new output stream. Very useful if, for example, you want to redirect all printed output to some kind of debugging log.

Example: in the code below, the do-stuff function will print to the debug output rather than standard out, but note that I didn't need to add an output parameter to do-stuff to enable this....

(defn do-stuff [] 
  (do-other-stuff)
  (print "stuff done!"))

(binding [*out* my-debug-output-writer]
  (do-stuff))

Note that Clojure's bindings are also thread-local, so you don't have an issue with concurrent usage of this capability. This makes bindings considerably safer than (ab)using global variables for the same purpose.

(Disclaimer: I've never programmed in a dynamic scoping language)

The scoping is much easier to implement and potentially faster. With dynamic scoping, only the one symbol table is needed (the variables currently available). It just reads from this symbol table for everything.

Imagine in Python the same function.

def bar():
    x = 42;
    foo(42)

def foo(x):
    print x

When I call bar, I put x into the symbol table. When I call foo, I take the symbol table currently used for bar and push it onto the stack. I then call foo, which has x passed to it (likely having been put into the new symbol table on calling the function). After exiting the function, I have to destroy the new scope and restore the old one.

With dynamic scoping, this isn't needed. I only need to know the instruction I need to return to when the function ends since nothing has to be done to the symbol table.

  • "Potentially faster" only in a (naive) interpreter; compilers can do much better with lexical scoping than they can with dynamic scoping. Also, "With dynamic scoping, this isn't needed...." is wrong: with dynamic scoping, when a variable's scope ends (eg, the function returns), you need to update the symbol table to restore its previous value. Actually, I think the code would typically refer directly to a "symbol object" that would have a mutable field for the variable's current value, much faster than doing a table lookup each time. But still, the update work doesn't just vanish. – Ryan Culpepper Aug 23 '11 at 20:21
  • Ah, I wasn't aware dynamic scoping would still restore the value from before the function was called. I thought they all referred to the same value. – jsternberg Aug 23 '11 at 20:25
  • 2
    yes, there is still nesting. Otherwise it would be equivalent to making every variable global and just doing a simple assignment to it. – Ryan Culpepper Aug 23 '11 at 20:43

Exception handling in most languages utilizes dynamic scoping; when an exception occurs control will be transferred back to the closest handler on the (dynamic) activation stack.

  • Please comment on the reason for the downvote. Thanks! – Eyvind Feb 13 '15 at 11:16
  • This is an interesting take. Would you also say that return statements in most languages use dynamic scoping, because they return control to the caller on the stack? – ruakh Oct 12 '17 at 3:12

Not 100% sure if this is an exact match, but I think it at least gets near enough in a general sense to show where it may can be of use to break or change scoping rules.

The Ruby language comes the templating class ERB, which for example in Rails is used to generate html files. If you use it looks like this:

require 'erb'

x = 42
template = ERB.new <<-EOF
  The value of x is: <%= x %>
EOF
puts template.result(binding)

The binding hands access to local variables to the ERB method call, so it can access them and use them to fill the template. (The code between the EOFs is a string, the part between <%= %> evaluated as Ruby code by ERB and would declare it's own scope like a function)

A Rails example even better demonstrates this. In an article controller, you would find something like this:

def index
  @articles = Article.all

  respond_to do |format|
    format.html
    format.xml  { render :xml => @posts }
  end
end

The index.html.erb file could then use the local variable @articles like this (in this case the creation of an ERB object and the binding are handled by the Rails framework, so you don't see it here):

<ul>
<% @articles.each do |article| %>
  <li><%= article.name</li>
<% end %>
</ul>

So by use of a binding variable, Ruby allows to run one and the same template code in different contexts.

The ERB class is only one example of usage. Ruby allows in general to get the actual state of execution with variable and method bindings by use of Kernel#binding, which is very useful in any context where you want to evaluate a method in different context or want to keep a context for later use.

The use cases for dynamic scoping are IHMO the same as for global variables. Dynamic scoping avoid some of the problems with global variables allowing for a more controlled update of the variable.

Some use cases that I can think of:

  • Logging: Makes more sense to group logs by runtime context that from a lexical context. You could dinamically bind the logger at a request handler so that all functions called from there share the same "requestID" in the log entries.
  • Output redirection
  • Resource Allocators: To keep track of resources allocated for a particular action/request.
  • Exception handling.
  • Contextual behaviour in general, e.g Emacs changing the key mapping in certain contexts.

Of course dynamic scoping is not "absolutely required" but relieves of the burden of having to pass tramp data along the call chain or having to implement smart global proxies and context managers.

But again, dynamic scoping comes handy when dealing with kind of elements that are many times treated as globals (logging, output, resource allocation/management, etc).

There pretty much aren't any. I sure hope that you, for example, never use the same variable twice.

void foo() {
    print_int(x);
}
void bar() {
    print_string(x);
}

Now how do you call both foo and bar from the same function?

This is effectively akin to simply using a global variable, and it's bad for all the same reasons.

  • 1
    x = 42; foo(); x = '42'; bar();? – Luc Danton Aug 24 '11 at 0:38

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.