This post originated from an RSS feed registered with Ruby Buzz
by .
Original Post: Dynamically Scoped Variables
Feed Title: cfis
Feed URL: http://cfis.savagexi.com/articles.rss
Feed Description: Charlie's Blog
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by
Latest Posts From cfis
Advertisement
Just as Peter continues to be amazed by Wikipedia, so do I. Today I noticed
that David Jenkins, who I used to work with, wrote an article about a programming
language called Magik that forms the basis of Smallworld GIS.
Magik was revolutionary for
its time - a dynamic/strongly typed object-oriented language used to build
large mission critical applications. It shares many similarities with Smalltalk
and Ruby, including mixins, closures, procs, etc.
And one thing it has that Ruby doesn't is dynamic variables. Dynamic variables
have been around a long time, LISP has them as does PERL. But if you've never
worked with dynamic variables they are a bit weird. At least I thought so.
The basic idea is that when you set the value of a variable it will override
any previous values for the remainder of that scope but then return back
to its original value at the end of the scope. Thus a dynamic variable acts
just like a stack.
int x = 0;
int f () { return x; }
int g () { int x = 1; return f(); }
If you call g() what's the result? Well, most people would say 0 which
is true for lexically scoped variables. But for dynamically scoped variables
it is 1. See why? In g we override the value of x and make it 1. That value
remains the current value as g calls f and accesses x. Once we return out
of g, x reverts back to its original value of 0.
Reading Paul Graham'sOn
Lisp, it turns out that LISP started with dynamically
scoped variables. However, it turns out that lexically scoped variable are
generally more useful because they are easier to understand and enable the
use of closures. If you think about it for a second, you'll see that dynamic
scoping doesn't work well with closures since the whole point of a closure
is to capture the current value of a variable.
So, why would you use dynamic variables? For the longest time I didn't see
much use for them. But in turns out they are quite useful in multi-threaded
applications. Imagine you've written a gis server (ala ArcIMS, MapServer
or Smallworld
IAS) and each client can request a map in a different projection.
That means that your map rendering code has to have access to the current
projection. One simple way to do this is via dynamic variables. Set the dynamic
variable at the start of the request and have the map rendering code access
its value. Something like this (in pseudo Magik no less!):
# Create a global variable
_global current_projection = 'epsg4326'
_method process_request
# Override the default value as a dynamic variable
_dynamic current_projection = 'epsg9822'
# Do some stuff
...
# Render map
self.render_map()
_endmethod
_method render_map
# Access dynamic variable
_if current_projection == 'epsg4326'
_endif
_endmethod
Although it looks like the render_map code is accessing a global variable,
it in fact is accessing a dynamically set variable. Thus this code is fully
thread safe.
For the case above you can fake dynamic variables by using thread-local
storage. In fact, Christian Neukirchen has
used this technique to implement dynamic
variables in Ruby.
Now, let's get back to my post yesterday
about Rails and HTML/XHTML generation. If you write an application server,
you'll found out sooner or later that just about every piece of code needs
access to the request and response objects. I suppose this might seem obvious,
but it took me 2 years and 3 release of SIAS to finally see the light. My
resistance was from fear of creating too tight a coupling between different
parts of the system.
Rails of course has the same issue. The general solution, and the one Rails
takes, is to pass around a reference to an object that holds the information
you need. For rails, that is the controller object which in turn has references
to the request and response objects. However, it doesn't work quite as well
as you would like, as I explained yesterday. And woe to you if you want to
change it - then you really are touching every part of the system.
In contrast, dynamic variables provide a cleaner solution.
All parts of the code have access to the necessary information, and you don't
have to pass object references as method parameters all over the place.
Thus you end up with less code, and in fact, less inter-module dependencies.
So although a seemingly obscure programming language construct, dynamically
scoped variables can come in handy in the right situations.