help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Differences between Elisp and Lisp


From: Kent M Pitman
Subject: Re: Differences between Elisp and Lisp
Date: 29 Apr 2003 11:43:12 -0400
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.2

Thomas Link <samul@web.de> writes:

> > I thought that CL already implemented lexical binding? At least within
> > a let form (or "lexical-let").
> 
> I guess it's faking lexical binding by replacing variable names with
> gensyms. This makes it pseudo-lexical but not more efficient.

In addition to having questionable efficiency issues, such a strategy
also eliminates the one primary reason that more than anything
justifies lexical scoping--the ability to know 'just by looking' that
no other uses of the variable exist and that it's ok to optimize.
Consider:

 (let ((x 1))
   (f x))

which might result from a macro expansion.  You'd like this to compile the
same as (f 1).  But if you just turn it into

 (let ((x0001 1))
   (f x0001))

the compiler still has to worry that x0001 might be accessible within the
definition of f, and so it can't make the binding for it go away. What 
allows you to make the binding go away is not the _fact_ that this is the 
only use of x0001 but the _lexically apparent knowledge_ that this is the
only use of x0001.  And that knowledge comes from 'real lexicality', not
from clever tricks.  [Even if you have access to the source code of 'f',
you can't rely on that since f might be later redefined.  It should be
possible to later introduce a new f with different properties without
recompiling callers to f.]

Additionally, tricks like the above mean that in error breaks, the stack
is cluttered with myriad special variable bindings that one really doesn't
want to have to paw through.

> > If emacs just went to using lexical binding in the large, I suspect
> > that it would cause lots of problems with existing packages. I have
> > used dynamic scoping to achieve ends in the past, which might be a bit
> > nasty, but it does work!
> 
> Correct me if I'm wrong, but e.g. Common Lisp has dynamic binding for
> variables defined with defvar. The following works with clisp:
> 
>       (defvar x 1)
>       (defun y (a) (+ x 1))
>       (y 1) => 2
>       (let ((x 10)) (y 1)) => 11
> 
> So one could have both. The question is, which one should be the
> "default" mode and which one should be subject to special constructs.

You are not wrong.  The above example will work fine in CL, though we usually
(by convention, not requirement) use *'s around a variable that is 'special'
(dynamically bound) so that people don't get confused.  We would usually
write:

 (defvar *x* 1)
 (defun y (a) (+ *x* 1))
 (y 1) => 2
 (let ((*x* 10)) (y 1)) => 11

Further, even a variable not defined with defvar can be on a one-time basis
bound dynamically in CL by declaring it locally special.  In this case, we
still encourage *'s, but it's more common for that to be violated. e.g.,

 (let ((x 1) (y 2))
   (declare (special x y))
   (eval '(+ x y))) => 3

Without the special declaration, this would signal an error since an x and
y bound lexically would not be visible to eval.  It would be easy for an
elisp based on cl to offer a macro like:

 (defmacro dynamic-let (bindings &body forms)
   `(let ,bindings
      (declare (special ,@(mapcar #'car bindings)))
      ,@forms))

so that

 (dynamic-let ((x 1) (y 2))
   (eval '(+ x y)))

would expand to the previous 'let' expression, in the rare case that a defvar
had not been done but a dynamic binding was still wanted.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]