Edit
Attach
Printable
topic end
<!-- * Set TOPICTITLE = Claus Brod: I'm so special (11 Feb 2006) --> <style type="text/css"> pre {background-color:#ffeecc;} </style> %STARTINCLUDE% <a name="11"></a> ---+++ [[BlogOnSoftware20060211][I'm so special]] (11 Feb 2006) <summary> The [[http://www.clausbrod.de/myjob.html][large application which I help to develop]] has an embedded Lisp interpreter and compiler, and over time I also left my marks in that subsystem. It was only after a considerable amount of tinkering with the innards of the interpreter that my insights into Lisp finally reached critical mass. I guess I understand now why Lispniks are so devoted to their language and why they regard all those other languages as mere Lisp wannabees. </summary> While learning Lisp, bindings and closures were particularly strange to me. It took me way too long until I finally grokked lexical and dynamic binding in Lisp. Or at least I _think_ I get it now. Let us consider the following C code: <pre> int fortytwo = 42; int shatter_illusions(void) { return fortytwo; } void quelle_surprise(void) { int fortytwo = 4711; printf("shatter_illusions returns %d\n", shatter_illusions()); } </pre> A seasoned C or C++ programmer will parse this code with his eyes shut and tell you immediately that =quelle_surprise= will print "42" because =shatter_illusions()= refers to the global definition of =fortytwo=. Meanwhile, back in the parentheses jungle: <pre> (defvar fortytwo 42) (defun shatter-illusions() fortytwo) (defun quelle-surprise() (let ((fortytwo 4711)) (format t "shatter-illusions returns ~A~%" (shatter-illusions)))) </pre> To a C++ programmer, this looks like a verbatim transformation of the code above into Lisp syntax, and he will therefore assume that the code will still answer "42". But it doesn't: =quelle-surprise= thinks the right answer is "4711"! Subtleties aside, the value of Lisp variables with _lexical binding_ is determined by the lexical structure of the code, i.e. how forms are nested in each other. Most of the time, [[http://www.lisp.org/HyperSpec/Body/speope_letcm_letst.html][let]] is used to establish a lexical binding for a variable. Variables which are _dynamically bound_ lead a more interesting life: Their value is also determined by how forms call each other at runtime. The [[http://www.lisp.org/HyperSpec/Body/mac_defparametercm_defvar.html][defvar]] statement above both binds =fortytwo= to a value of 42 _and_ declares the variable as _dynamic_ or _special_, i.e. as a variable with dynamic binding. Even if code is executed which usually would bind the variable lexically, such as a =let= form, the variable will in fact retain its dynamic binding. "Huh? What did you say?" 1 =defvar= declares =fortytwo= as dynamic and binds it to a value of 42. 2 The =let= statement in =quelle-surprise= binds =fortytwo= to a value of 4711, but does not change the _type_ of binding! Hence, =fortytwo= still has dynamic binding which was previously established by =defvar=. This is true even though =let= _usually_ always creates a lexical binding. 3 =shatter-illusions=, when called, inherits the dynamic bindings of the calling code; hence, =fortytwo= will still have a value of 4711! Kyoto Common Lisp defines =defvar= as follows: <pre> (defmacro defvar (var &optional (form nil form-sp) doc-string) `(progn <b>(si:make-special ',var)</b> ,(if (and doc-string *include-documentation*) `(si:putprop ',var ,doc-string 'variable-documentation)) ,(if form-sp `(or (boundp ',var) (setq ,var ,form))) ',var)) </pre> In the highlighted form, the variable =name= is declared as [[http://www.lisp.org/HyperSpec/Body/dec_special.html#special][special]], which is equivalent with dynamic binding in Lisp. This effect is quite surprising for a C++ programmer. I work with both Lisp and C++, switching back and forth several times a day, so I try to minimize the number of surprises a much as I can. Hence, I usually stay away from special/dynamic Lisp variables, i.e. I tend to avoid =defvar= and friends and only use them where they are really required. Unfortunately, =defvar= and =defparameter= are often recommended in Lisp tutorials to declare global variables. Even in these enlightened times, there's still an occasional need for a global variable, and if you follow the usual examples out there, you'll be tempted to quickly add a =defvar= to get the job done. Except that now you've got a dynamically bound variable without even really knowing it, and if you expected this variable to behave like a global variable in C++, you're in for a surprise: <pre> > (print fortytwo) 42 42 > (quelle-surprise) shatter-illusions returns 4711 NIL > (shatter-illusions) 42 > (print fortytwo) 42 42 </pre> So you call =shatter-illusions= once through =quelle-surprise=, and it tells you that the value of the variable =fortytwo=, which is supposedly global, is 4711. And then you call the same function again, only directly, and it will tell you that this time =fortytwo= is 42. The above code violates a very useful convention in Lisp programming which suggests to mark global variables with asterisks (=*fortytwo*=). This, along with the guideline that global variables should only be modified using =setq= and =setf= rather than =let=, will avoid most puzzling situations like the above. Still, I have been confused by the dynamic "side-effect" of global variables declared by =defvar= often enough now that I made it a habit to question any =defvar= declarations I see in Lisp code. More on avoiding global dynamic variables [[BlogOnSoftware20060218][next time]]. * [[http://www.gigamonkeys.com/book/functions.html][Practical Common Lisp: Functions]] * [[http://www.flownet.com/gat/specials.pdf][The Idiot's Guide to Special Variables and Lexical Closures]] %COMMENT{type="below" nonotify="on"}% --- %STOPINCLUDE%
to top
End of topic
Skip to action links
|
Back to top
Edit
|
Attach image or document
|
Printable version
|
Raw text
|
Refresh
|
More topic actions
Revisions: | r1.8 |
>
|
r1.7
|
>
|
r1.6
|
Total page history
|
Backlinks
You are here:
Blog
>
BlogOnSoftware20060211
r1.8 - 05 Jan 2008 - 08:53 -
ClausBrod
to top
Blog
This site
2017
:
12
-
11
-
10
2016
:
10
-
7
-
3
2015
:
11
-
10
-
9
-
4
-
1
2014
:
5
2013
:
9
-
8
-
7
-
6
-
5
2012
:
2
-
10
2011
:
1
-
8
-
9
-
10
-
12
2010
:
11
-
10
-
9
-
4
2009
:
11
-
9
-
8
-
7
-
6
-
5
-
4
-
3
2008
:
5
-
4
-
3
-
1
2007:
12
-
8
-
7
-
6
-
5
-
4
-
3
-
1
2006:
4
-
3
-
2
-
1
2005:
12
-
6
-
5
-
4
2004:
12
-
11
-
10
C++
CoCreate Modeling
COM & .NET
Java
Mac
Lisp
OpenSource
Scripting
Windows
Stuff
Changes
Index
Search
Maintenance
Impressum
Datenschutzerklärung
Home
Webs
Atari
Blog
Claus
CoCreateModeling
Klassentreffen
Main
Sandbox
Sommelier
TWiki
Xplm
Jump:
Copyright © 1999-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki?
Send feedback