functionlambdascopeelisplexical-scope

Emacs Lisp variables scoping


Let's consider the following functions:

    (defun test (x)
      "X."
      (request "http://example.com"
        :parser 'json-read
        :complete (cl-function
                   (lambda (&key response &allow-other-keys)
                     (message "%s" x)))))

    (defun test2 (x)
      "X."
      (funcall (cl-function (lambda (z) (message "%s" z))) x))

Calling (test2 3) Works fine and produces the desired message. Calling (test 3), however, fails with the following error:

error in process sentinel: let*: Symbol’s value as variable is void: x
error in process sentinel: Symbol’s value as variable is void: x

My guess is that request is a macro doing something weird to variable scoping. Unfortunately, the documentation does not mention anything like this. Is there a way to overcome that?


Solution

  • request is probably an ordinary function.

    The problem is that the lambda you pass to it is not called immediately but is saved and called later:

    (defun make-function (x)
      (lambda () (message "received %s" x)))
    => make-function
    (defconst f (make-function 3))
    => f
    (funcall f)
    => Lisp error: (void-variable x)
    

    x that make-function bound no longer exists.

    This is because by default Emacs uses dynamic binding and you need lexical binding to get the behavior you want.

    If you add

    ;; -*- lexical-binding:t -*-
    

    to the first line of your file, it will be compiled with lexical binding and the code above will produce the message received 3 instead of an error.