SDS <···········@cctrading.com> writes:
> In emacs lisp one can do
> (let ((float-output-format "%.5f"))
> (whatever))
> to set float-output-format temporary and reset it to the original value
> afterwards.
What you're asking for is what you get with "special" (sometimes
called "dynamic") variables in Common Lisp. Your claim that it's not
available is incorrect; the syntax is just different. Try:
(setq foo 1)
(defun bar ()
(declare (special foo))
foo)
(let ((foo 2))
(declare (special foo))
(bar))
Normally, to avoid writing (declare (special <var1> <var2> ...)) we use
(proclaim '(special <var1> <var2> ...)). ALSO, we by convention,
to avoid visual confusion in the code, name the variables we will
proclaim special with *'s around them. e.g., *foo*
This keeps someone from confusing them visually since they have very
different properties. Nothing in the language keeps you from writing
(proclaim '(special foo bar)) but it will confuse people later when FOO
and BAR don't work as expected. So we say to do
(proclaim '(special *foo* *bar*)) and then use variables *foo* and
*bar* in the way you're talking about. DEFVAR and DEFPARAMETER both
proclaim their variables specially in this way.
Try:
(defvar *foo* 1)
(defun bar () *foo*)
(let ((*foo* 2)) (bar))
The reason all variables are not special is that they used to be a
long time ago and it was cause of massive numbers of program errors.
Special variables have their place but should be used with caution.
It is easier to prove a program correct if it uses only lexical
variables because you know its choice of bindings can't affect
functions it calls.
For example, (defun foo (x) (bar))
in emacs lisp can accidentally break bar if bar relies on a free x.
But in Common Lisp, (defun foo (x) (bar)) can't break bar because
bar can't be using the x that foo uses. You have to do
(defvar *x* ...)
(defun foo (*x*) (bar))
or
(defun foo (x) (declare (special x)) (bar))
but in either case you're explicitly accepting the risk of affecting
bar. The problem in emacs lisp is that there is no way to say when
you are INTENDING to influence your callers and when you are not.
CL allows you to make that choice explicitly. Many programming
languages only allow lexical variables.
Also, by the way, the example you gave with UNWIND-PROTECT won't work
under multi-threaded lisps because the binding will be seen in
processes that have not called your WITH macro. Special variable
binding (described above) will, however, be correctly handled in all
multi-threaded Lisps I'm aware of.