19

Some elisp functions that I have installed generate warnings:

`flet' is an obsolete macro (as of 24.3); use either `cl-flet' or `cl-letf'.

Is it dangerous if I simply replace all flet with cl-flet? If it is OK to replace them, which one is better?

If it is not dangerous to replace it, I'd send pull requests to the projects.

Is there some reason that they don't change it?

zkilnbqi
  • 1,141
  • 11
  • 23
ironsand
  • 14,329
  • 17
  • 83
  • 176

4 Answers4

11

flet isn't the same as either cl-flet or cl-letf. It's more dangerous (and maybe more powerful). That's why it's being deprecated.

Since it's different (binds dynamically a function name), you have to think in each case if it's appropriate to replace it with cl-flet.

Small example when flet can't be replaced with cl-flet

(defun adder (a b)
  (+ a b))

(defun add-bunch (&rest lst)
  (reduce #'adder lst))

(add-bunch 1 2 3 4)
;; 10

(flet ((adder (a b) (* a b)))
  (add-bunch 1 2 3 4))
;; 24

(cl-flet ((adder (a b) (* a b)))
  (add-bunch 1 2 3 4))
;; 10

Note that cl-flet does lexical binding, so the behavior of adder isn't changed, while flet does dynamic binding, which makes add-bunch temporarily produce a factorial.

abo-abo
  • 20,038
  • 3
  • 50
  • 71
  • I see. So, it's not easy as I can simply replace all functions. Thanks! – ironsand Sep 19 '13 at 13:22
  • 2
    If you want to decrease your annoyance level, just rip out the definition of `flet` from the source, strip the `obsolete` and put it in your .emacs. It should be the job of package writer to remove `flet` not yours. – abo-abo Sep 19 '13 at 13:27
  • 1
    Another option is `(setq byte-compile-warnings '(not obsolete))` – juanleon Sep 19 '13 at 13:51
  • 1
    Byte compile warnings are very useful in my opinion, so I don't disable them. They're great at capturing variable typos or malformed let bindings. But there's nothing I can do, as far as I know, about `flet` warning short of rewriting the package api. – abo-abo Sep 19 '13 at 14:10
  • This post might also help understanding: http://stackoverflow.com/a/9106395/729907 – Drew Sep 19 '13 at 16:02
  • @abo-abo, my suggestion was only for one specific kind of warning (obsolete), all the rest are still in. A safe option is to "around defadvice" package-install with a `(let ((byte-compile-warnings '(not obsolete))) ad-do-it)`, if you get your third party libraries via package-install. – juanleon Sep 20 '13 at 07:50
  • I see, I've misunderstood. But obsolete function warnings good: when I'm writing some new code and using some function that I've just learned, it's nice to get a warning "Don't use this function: it will be disabled soon". – abo-abo Sep 20 '13 at 07:56
  • 1
    Is there a way to get the old behaviour without using flet then? – Clément Feb 22 '15 at 20:56
6

I've recently wrote a post on the subject. The gist of the post is that the best replacement for flet (if you need dynamic binding) is noflet. It's a third party library, but it's almost a drop-in replacement for flet (while adding some extra capabilities).

Bozhidar Batsov
  • 55,802
  • 13
  • 100
  • 117
5

The cl-letf function can be used for dynamic binding of functions, as Artur describes in this blog entry.

Alastair
  • 4,475
  • 1
  • 26
  • 23
1

You could modify your function to use lawlist-flet or create an alias -- all I did was remove the warning and rename the flet macro to lawlist-flet:

;;;;;;;;;;;;;;;;;;;;;;;;;;;; FLET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defmacro lawlist-flet (bindings &rest body)
      "Make temporary overriding function definitions.
    This is an analogue of a dynamically scoped `let' that operates on the function
    cell of FUNCs rather than their value cell.
    If you want the Common-Lisp style of `flet', you should use `cl-flet'.
    The FORMs are evaluated with the specified function definitions in place,
    then the definitions are undone (the FUNCs go back to their previous
    definitions, or lack thereof).
    \(fn ((FUNC ARGLIST BODY...) ...) FORM...)"
      (declare (indent 1) (debug cl-flet)
    ;;           (obsolete "use either `cl-flet' or `cl-letf'."  "24.3")
                    )
      `(letf ,(mapcar
               (lambda (x)
                 (if (or (and (fboundp (car x))
                              (eq (car-safe (symbol-function (car x))) 'macro))
                         (cdr (assq (car x) macroexpand-all-environment)))
                     (error "Use `labels', not `flet', to rebind macro names"))
                 (let ((func `(cl-function
                               (lambda ,(cadr x)
                                 (cl-block ,(car x) ,@(cddr x))))))
                   (when (cl--compiling-file)
                     ;; Bug#411.  It would be nice to fix this.
                     (and (get (car x) 'byte-compile)
                          (error "Byte-compiling a redefinition of `%s' \
    will not work - use `labels' instead" (symbol-name (car x))))
                     ;; FIXME This affects the rest of the file, when it
                     ;; should be restricted to the flet body.
                     (and (boundp 'byte-compile-function-environment)
                          (push (cons (car x) (eval func))
                                byte-compile-function-environment)))
                   (list `(symbol-function ',(car x)) func)))
               bindings)
         ,@body))
lawlist
  • 13,099
  • 3
  • 49
  • 158