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.
Let’s take a look at an example from Wikipedia:
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’s On 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.