19

I have some code that uses flet to temporarily change the behaviour of functions.

;; prevent changing the window
(flet ((pop-to-buffer (buffer &rest args)
                      (switch-to-buffer buffer)))
   (compilation-next-error-function n reset))

However, Emacs' byte compiler gives a warning:

In ag/next-error-function:
ag.el:103:7:Warning: `flet' is an obsolete macro (as of 24.3); use either
    `cl-flet' or `cl-letf'.

However, cl-flet works differently and doesn't suit some use cases, and I believe this is one of those cases.

The options I can see are:

  1. Tell Emacs to ignore the warning somehow.

  2. Roll my own flet.

  3. Use noflet or dflet.

What is the best approach?

2
  • 4
    "However, cl-flet works differently". There's a second suggestion in that warning message. ;-)
    – Malabarba
    Commented Nov 12, 2014 at 19:31
  • I took the old one and just renamed it (e.g., my-flet) and removed the obsolete warning, and use that in in any package that previously required flet.
    – lawlist
    Commented Nov 12, 2014 at 19:54

2 Answers 2

14

To get the same behavior you're used to with flet, use cl-letf to change a symbols function value.

(cl-letf (((symbol-function 'pop-to-buffer)
           (lambda (buffer &rest _) (switch-to-buffer buffer))))
  (compilation-next-error-function n reset))

If you were to roll your own flet, the easy way would be macro that expands to a cl-letf form.

Edit: rolled it

(defmacro myflet (bindings &rest body)
  "Works like the old `flet'. Does not validate form structure."
  (declare (indent defun))
  `(cl-letf ,(mapcar (lambda (binding)
                       `((symbol-function ',(car binding))
                         (lambda ,(cadr binding) ,@(cddr binding))))
                     bindings)
     ,@body))

(myflet ((+ (&rest args) (apply '- args)))
  (+ 10 3 2)) ;; => 5
1
  • 4
    However, keep in mind the caveat from Yann Hodique's comment to Malabarba's article: "note that Emacs 24.3.1 has a subtle bug that makes cl-letf not a proper alternative (IIRC, it does not work for flet-ing symbols that are not already fboundp). Which is why a backward-compatible version of flet is a bit... convoluted."
    – phils
    Commented Nov 13, 2014 at 21:32
14

Artur Malabarba wrote this up recently, in Understanding letf and how it replaces flet.

letf is an alias for cl-letf, and while it's most likely what you want, there's a minor caveat which Artur points out:

Unfortunately, cl-flet is not identical to the original flet—it's lexical, not dynamic.

(Nic's noflet package provides extended functionality along these lines.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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