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

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

Re: Real-life examples of lexical binding in Emacs Lisp


From: Pascal J. Bourguignon
Subject: Re: Real-life examples of lexical binding in Emacs Lisp
Date: Fri, 29 May 2015 14:28:13 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux)

Marcin Borkowski <mbork@mbork.pl> writes:

> Hi all,
>
> I googled a bit, and could not find /real-world/ examples of using
> lexical binding and its advantages /in Emacs Lisp/.  I understand that
> it's a nice thing to be able to create closures, and that lexical
> binding is in general faster than dynamic binding (which is a bonus in
> itself), but could anyone show me a real /text editing/ problem that
> lexical binding solves, like something that is easier done with
> l.b. than with d.b.?  (Examples of general-purpose programming problems
> made easier with l.b. are more or less obvious/easy to find, but Emacs
> is a text editor, after all, and this is its primary area.)

Lexical binding matters for two things:

- it allows the creation of closures.
- it prevents the clobbering of variables.


Closures:

    A typical example, is visible in the thread "~`symbol-function' to
    get code as list even when byte-compiled?":

    ;;;; -*- mode:emacs-lisp;lexical-binding:t;coding:utf-8 -*-
    (defun add-one-shot-meat (hook fun)
      (let ((name (gensym)))
        (setf (symbol-function name)
              (lambda ()
                (remove-hook hook name)
                (funcall fun)))
        (add-hook hook name)))

    Without lexical binding, fun and hook would be dynamic, and
    therefore their bindings would disappear when add-one-shot-meat
    returns.  Therefore they would be undefined variable when the 
    function is called, or worse, they may be bound at that time by some
    other function to something different.

    Compare:

        (setf lexical-binding t)

        (defun e (f)
          (let ((v 42))
             (funcall f)))

        (let ((v 33))
          (e (lambda () v)))

        --> 33


        (setf lexical-binding nil)

        (defun e (f)
          (let ((v 42))
             (funcall f)))

        (let ((v 33))
          (e (lambda () v)))

        --> 42


Clobering variables:
  
    For example, if we have a package such as:

        (setf lexical-binding nil)
        (defun d () v)
        (defun e (f)
          (let ((v 42))
             (funcall f)))

    and we used it with a function in another package such as:

        (defun h ()
           (let ((v 33))
             (d)))
 
    we obtain:

         (e (function h))
         --> 33

    instead of the expected 42.

    Hence the workaround of prefixing all variables by the package name,
    but this is often insufficient (because package names being often
    generic, a different package may name its internal variables
    similarly) and not always applied, notably for internal variables.

    To be 100% safe without lexical binding, you would have to prefix
    ALL your variables with very long package and function name
    prefixes.


-- 
__Pascal Bourguignon__                 http://www.informatimago.com/
“The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.” -- Carl Bass CEO Autodesk


reply via email to

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