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

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

Re: Are there any problems with lexical-let or other cl-macros???


From: Pascal J. Bourguignon
Subject: Re: Are there any problems with lexical-let or other cl-macros???
Date: Wed, 08 Dec 2010 15:10:53 -0000
User-agent: Gnus/5.101 (Gnus v5.10.10) Emacs/23.1 (darwin)

LanX <lanx.perl@googlemail.com> writes:

> Hi
>
> http://steve-yegge.blogspot.com/2008/11/ejacs-javascript-interpreter-for-emacs.html
> steve yegge complains about missing lexical vars roughly giving this
> example
>
> (require 'cl)
> (defun foo ()
>   (setq x 7))
>
> (defun bar ()
>   (let ((x 6))
>     (foo)
>     x))  ; you would expect x to still be 6 here
>
> (message (number-to-string (bar)))
>
> What I don't understand is that simply replacing let with lexical-let
> will solve the problem.

Esthetically, but the implementation is not efficient, and cannot be
since the emacs VM (which is a very high level lisp VM) doesn't
provide a way to implement lexical binding at all AFAIK (well perhaps
using a lisp vector and mapping variables to offsets, but this
probably would not be more efficient either).

Let's compare the emacs VM (I introduce a (setf x (+ x x)) form to
have both compiler generate more comparable code, clisp compilers
optimizes out the original let):

    (disassemble (byte-compile (defun* bar ()
                                 (lexical-let ((x 3))
                                   (setf x (+ x x))
                                   (foo)
                                   x))))
    byte code:
      args: nil
    0       constant  3
    1       varbind   --cl-x--
    2       constant  --cl-x--
    3       symbol-value 
    4       constant  --cl-x--
    5       symbol-value 
    6       plus      
    7       varset    --cl-x--
    8       constant  foo
    9       call      0
    10      discard   
    11      constant  --cl-x--
    12      symbol-value 
    13      unbind    1
    14      return    

    (Note that these occurences of --cl-x-- above are all the same
    symbol, but it's not interned, so in a different (let ((x ...))
    ...) it would be a different --cl-x-- symbol; we could have used a
    symbol named x too).


With the clisp VM:

    (disassemble (compile (defun bar ()
                            (let ((x 3))
                              (setf x (+ x x))
                              (foo)
                              x))))
    WARNING in BAR :
    Function FOO is not defined

    Disassembly of function BAR
    (CONST 0) = 3
    (CONST 1) = FOO
    0 required arguments
    0 optional arguments
    No rest parameter
    No keyword parameters
    7 byte-code instructions:
    0     (CONST&PUSH 0)                      ; 3
    1     (LOAD&PUSH 0)
    2     (LOAD&PUSH 1)
    3     (CALLSR&STORE 2 55 0)               ; +
    7     (CALL0 1)                           ; FOO
    9     (POP)
    10    (SKIP&RET 1)
    NIL


In the case of the emacs VM, it has to establish a dynamic binding
with varbind, which is rather costly.  References to variables must go
thru the symbol: you need to keep the symbols around (space), and it
goes thru the symbol (time, one indirection).

In the case of the clisp VM,  for lexical references  the compiler can
drop the variable name (spare the symbol), and the references to the
lexical variable is done by direct addressing (relative to the frame,
or in the case of clisp, the stack).  

clisp byte code is of lower level than emacs byte code, but it is
bound to be more efficient at run-time.  On the other hand, the clisp
compiler is more complex than the emacs byte-compiler.


-- 
__Pascal Bourguignon__
http://www.informatimago.com


reply via email to

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