Home > Software engineering >  Emacs Lisp variables scoping
Emacs Lisp variables scoping

Time:10-29

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?

CodePudding user response:

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.

  • Related