In GNU CLISP 2.49.92, the following code:
(defvar i 1)
(defun g ()
(format T "g0:~d~%" i)
(setf i 2)
(format T "g1:~d~%" i))
(defun f ()
(setf i 3)
(format T "f0:~d~%" i)
(g)
(format T "f1:~d~%" i))
(f)
gives the following output:
f0:3
g0:3
g1:2
f1:2
NIL
Similarly, the following code in C:
#include <stdio.h>
static int i = 1;
int g (void) {
printf("g0:%d\n", i);
i = 2;
printf("g1:%d\n", i);
}
int f (void) {
i = 3;
printf("f0:%d\n", i);
g();
printf("f1:%d\n", i);
}
int main() {
f();
return 0;
}
gives the following output:
f0:3
g0:3
g1:2
f1:2
According the the documentation that I found, defvar creates a special variable that is dynamically scoped. On the other hand, C is a statically scoped language. And yet, the two pieces of code give the same output. What then is the difference between a Special Variable and a Global Variable?
The difference is that a special variable is dynamically scoped: any binding of that name is visible to any code that runs during the dynamic extent of that binding, whether or not that binding is lexically visible to the code.
In what follows I am skating over some things: see notes at the end for some hints as to what I've skated over.
It's important to understand the difference between a binding and an assignment, which is often confused in various languages (notably Python, but not really C):
So, in C:
C calls bindings 'declarations'.
In Lisp (by which I will mean 'Common Lisp' here & below), bindings are created by a small number of primitive binding forms: functions bind their arguments,
letestablishes bindings and there are some other forms perhaps. Existing bindings are mutated by, ultimately,setqand some other operators perhaps:setfis a macro which expands tosetqin simple cases.C does not have dynamic bindings: if my
gfunction called some functionhthen ifhtried to refer toiit would either be an error or it would be referring to some globali.But Lisp does have such bindings, although they are not used by default.
So if you take the default case, bindings work the same way as C (in fact, they don't, but the difference does not matter here):
In this case you can tell, just by looking (which is what 'lexical' means) which bindings are visible, and which assignments mutate which bindings.
Something like this code would be an error (technically: is undefined behaviour, but I will call it 'an error'):
It's an error because (assuming there's no global binding of
i),hcan't see the binding established bygand so cannot mutate it. This is not an error:But calling
gwill return2, not3becausehis mutating the binding it creates, not the bindinggcreated.Dynamic bindings work very differently. The normal way to create them is to use
defvar(ordefparameter) which declares that a given name is 'globally special' which means that all bindings of that name are dynamic (which is also called 'special'). So consider this code:Calling
gwill return2. And in this case:Calling
gwill return4, becausehhas mutated the dynamic binding of*i*established byg. What will this return?Dynamic bindings are very useful where you want some dynamic state to be established for a computation. For instance imagine some system which deals with transactions of some kind. You might write this:
Note that
*current-transaction*is essentially a bit of 'ambient state': any code in the dynamic scope of a transaction can see it but you don't have to spend some fantastic amount of work to pass it down to all the code. And note also that you can't do this with globals: you might think that this will work:And it will, superficially ... until you get an error which leaves
*current-transaction*assigned to some bogus thing. Well you can deal with that in CL:The
unwind-protectform will mean that*current-transaction*always gets assigned tonilon the way out, regardless of whether an error happened. And that seems to work even better ... until you start using multiple threads, at which point you die screaming, because now*current-transaction*is shared across all the threads and you're just doomed (see below): If you want dynamic bindings, you need dynamic bindings, and you can't, in fact, fake them up with assignments.One important thing is that, because CL does not textually distinguish between operations on dynamic bindings and those on lexical bindings, it's important that there should be a convention about names, so when you read code you can understand it. For global dynamic variables, this convention is to surround the name with
*characters:*foo*notfoo. It's important to use this convention if you do not want to fall into a pit of confusion.I hope that is enough both to understand what bindings are, how they differ from assignments, and what dynamic bindings are and why they're interesting.
Notes.
(defvar *foo*): this declares that*foo*is a dynamic variable, but doesn't give it an initial value: it is globally dynamic, but globally unbound.There will be other things I have missed.