5

Emacs' byte-compiler can tell me if I call pure functions without saving the result:

(defun foo-calls-add ()
  ;; value returned from (+ 1 2) is unused:
  (+ 1 2)
  12)

However, I don't get any warnings when I define my own pure functions:

(defun foo-pure (x)
  (declare (pure t) (side-effect-free error-free))
  x)

(defun foo-calls-pure ()
  ;; No warning here:
  (foo-pure 1)
  12)

What do I need to do in order for the byte compiler to warn about foo-calls-pure?

I've compared (symbol-plist '+) with (symbol-plist 'foo-pure) and I can't see any obvious missing properties.

6

If you look in byte-optimize-form-code-walker, you can see that a warning is printed for side-effect-free functions, but error-free functions just get optimized out and logged (not warned) only. Logging means it only shows up if have byte-optimize-log set to non-nil (you'll want to set it to source otherwise there's a lot of noise).

      ((and for-effect (setq tmp (get fn 'side-effect-free))
            (or byte-compile-delete-errors
                (eq tmp 'error-free)
                (progn
                  (byte-compile-warn "value returned from %s is unused"
                                     (prin1-to-string form))
                  nil)))
       (byte-compile-log "  %s called for effect; deleted" fn)
       ;; appending a nil here might not be necessary, but it can't hurt.
       (byte-optimize-form
        (cons 'progn (append (cdr form) '(nil))) t)

Additionally, the declaration doesn't take effect during compilation unless you use eval-when-compile, so you'll need something like:

(eval-and-compile
  (defun foo-pure (x)
    (declare (pure t) (side-effect-free t))
    x))

Or to avoid putting the whole defun inside eval-and-compile:

(eval-and-compile (function-put 'foo-pure 'side-effect-free 't))
  • "the declaration doesn't take effect during compilation", aha, that's a subtlety that I completely missed. Is this documented, or did you just look at the code? – Wilfred Hughes Nov 2 '16 at 5:05
  • 1
    Actually I just guessed & checked that one. It doesn't seem like great behaviour, perhaps worth a bug report to change the declare expansion to use eval-and-compile. – npostavs Nov 2 '16 at 14:41
  • 1
    Awesome, so that works nicely. If foo-pure is in a separate library that's byte-compiled, then downstream consumers will get the error without me doing function-put. – Wilfred Hughes Nov 3 '16 at 0:19
  • 1
    I've opened an Emacs bug too. I've proposed a patch but changing defun-declarations-alist in my current Emacs instance doesn't fix the issue. – Wilfred Hughes Nov 3 '16 at 1:05

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.