8

When executing the following I get an error:

(defun caller (func)
  (url-retrieve "http://m0smith.freeshell.org/"
   (lambda (status) (funcall func))))


(caller (lambda() (message "called")))

Result:

error in process filter: Symbol's value as variable is void: func

What is the best way to solve this problem? Basically I need to accept a callback from somewhere else, wrap it in another lambda and use that as the callback to url-retrieve.

If I change caller to

(defun caller (func)
  (url-retrieve "http://m0smith.freeshell.org/"
   `(lambda (status) (funcall ,func))))

it works. However, I cannot do this as func is being passed by flycheck and the macro expansion breaks it. To see the full context of what I am doing: https://gist.github.com/m0smith/b5961fda6afd71e82983

  • What macro expansion? Your last paragraph is unclear. Post here a full explanation of the problem. Using backquote with comma is the solution (one solution). Another could be to use lexical-let or setting variable lexical-binding. Please make clear what the problem is with the not-shown "macro". – Drew Dec 10 '14 at 15:20
  • I assumed the ` and , were macro expanded. Whatever that form is called then. I would like to work in EMACS 23. Is there a lexical feature available? – M Smith Dec 10 '14 at 15:23
  • If there is no use of FUNC beyond the funcall then logically you do not need lexical binding here. There is nothing wrong with using it, but you do not need it, unless some code actually needs to make use of the variable FUNC. If you do not need it (which is what it looks like, so far), then just replace its occurrence by its value, using backquote with comma. – Drew Dec 10 '14 at 15:23
  • Lexical binding is available in Emacs 23 (and prior), using lexical-let. The global variable lexical-binding is available in Emacs 24. – Drew Dec 10 '14 at 15:25
5

You can achieve this locally by using cl.el's lexical-let:

(eval-when-compile '(require 'cl))

(defun my-test-caller (func)
  (lexical-let ((ext-func func))
    (url-retrieve "http://www.google.com"
                  (lambda (status) (funcall ext-func)))))

(my-test-caller #'(lambda() (message "called")))

To be explicit as the help says:

Like `let', but lexically scoped.
The main visible difference is that lambdas inside BODY will create
lexical closures as in Common Lisp.

Now you can get the same effect by enabling lexical-binding which was added in Emacs 24.1. This is a buffer local variable that can be set and will enable lexical closures on all code in the buffer. So your buffer would look like this:

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

(defun my-lexical-test-caller (func)
  (url-retrieve "http://www.google.com"
                (lambda (status) (funcall func))))

(my-lexical-test-caller
 #'(lambda()
     (message "called from lexical-binding def")))
  • Thanks. However I get my-test-caller: Symbol's function definition is void: lexical-let in my emacs: GNU Emacs 24.4.1 (x86_64-w64-mingw32)` of 2014-10-20 on KAEL – M Smith Dec 10 '14 at 15:24
  • @MSmith - ahh add (require 'cl) – stsquad Dec 10 '14 at 15:27
  • lexical-let is defined in cl-macs.el. So (eval-when-compile '(require 'cl)) – Drew Dec 10 '14 at 15:27
  • You don't need to require cl.el at runtime, just for this. lexical-let is a macro, so it is enough to require it at compile time. – Drew Dec 10 '14 at 15:28
  • 2
    Please don't. Use lexical-binding. Flycheck doesn't support Emacs 23 anyway, so there's no point in trying to be compatible with it. – lunaryorn Dec 10 '14 at 15:51
5

Enable lexical-binding for your library, with M-x add-file-local-variable-prop-line RET lexical-binding RET t.

Please do not use lexical-let as suggested by the other answer. Flycheck itself is not compatible with Emacs 23, so there is no point in trying to maintain Emacs 23 compatibility in your own code.

  • Thanks. That will help so I am not trying to get the older emacs working for no reason – M Smith Dec 10 '14 at 16:22
  • What's wrong with using lexical-let for this? – stsquad Dec 11 '14 at 10:28
  • @stsquad It's slower and more verbose. With lexical-binding there is no need for an additional binding, because the argument itself is lexically scoped. Moreover, lexical-binding creates true closures, whereas lexical-let uses uninterned symbols to emulate lexical binding. – lunaryorn Dec 11 '14 at 11:38
  • @lunaryorn: isn't there a risk by enabling lexical-binding on a existing buffer of legacy code you may get unforeseen effects? Anyway I've expanded my answer to mention both solutions. – stsquad Dec 11 '14 at 12:00
  • @stsquad Yes, there could be unforeseen effects in poorly written legacy code which relies on let binding undefined variables dynamically. But again, Flycheck is for Emacs 24 anyway, so we are not talking about legacy code. – lunaryorn Dec 11 '14 at 12:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.