1

Assuming that the symbol foo is not defined nor declared with a defvar or let form, the following code generates a byte-compiler warning in Emacs 26.3 and 27.2:

(defun f-or ()
  "Use or."
  (when (or (null (boundp 'foo))
            (null foo))  ;=> ``Warning: reference to free variable ‘foo’``
    (message "foo is not set")))

However, the following, longer, but de Morgan equivalent code does not generate a byte-compiler warning:

(defun f-and ()
  "Use and."
  (when (null (and (boundp 'foo)
                  foo))         ; no warning here!
    (message "foo is not set")))

Replacing null for its alias not, using (unless X ...) instead of (when (not X) ... changes nothing, as expected.

Question: Why does Emacs byte-compiler generate a warning for the expression using the or form but not for the expression using the and form? Should this be reported as a byte compiler improvement request to not generate this invalid warning in both cases?

7
  • Because that's the way the byte-compiler is coded? ;-) BTW, (when (null X)...) is equivalent to (unless X ...).
    – Drew
    Jul 26, 2021 at 18:35
  • @Drew I used this example instead of unless because in my code, these are part of a longer boolean expression. I just extracted the relevant part. If the byte compiler is coded that way then wouldn't you think this applies as an improvement request to the byte compiler warning generation part?
    – PRouleau
    Jul 26, 2021 at 18:39
  • /me thinks the warning is valid: there is a reference to a free variable in each case. The problem is the absence of the warning in the and case.
    – NickD
    Jul 26, 2021 at 20:44
  • 4
    @NickD The absence of a warning in the and case is intentional, forms the basis of the bound-and-true-p macro, and also applies to fboundp. Checking whether a variable or function is defined and conditionally using it in that case is quite a common pattern in Elisp, especially for achieving forward/backward compatibility, so the byte-compiler is right not to complain in such cases. Any shortcomings of this feature should be reported via M-x report-emacs-bug, if they haven't already been.
    – Basil
    Jul 26, 2021 at 20:57
  • My comment was directed towards the OP's "invalid warning" characterization. I just wanted to point out that the warning is valid in both cases - OTOH, describing its absence as a "problem" was ill-informed on my part. Thanks for the explanation!
    – NickD
    Jul 26, 2021 at 21:26

1 Answer 1

2

After submitting a bug report for this that was rejected I better understand the overall intent of the byte compiler as it was best described by Lars Ingebrigtsen in his closing remark:

"The issue isn't that the compiler warning is wrong -- it's correct; but we suppress it in very particular situations where it'll obviously not lead to any problems."

The byte-compiler is inconsistent in its warning generation but that's an implementation decision.

  • In both scenarios above the code will run without errors but in both case the foo symbol is unbound (a free variable) and a warning reporting it as a free variable is not incorrect.

  • The implementers of the byte-compiler have chosen to inhibit the warning in valid code scenarios that are often seen, but not all.

  • That's a implementation decision as valid as any other that I hope this question/answer ticket will clarify for others that might run into this.

Now the easy way out to prevent this byte-compiler warning is to place a (defvar foo) form above the code, something I did not mention before because I wanted to concentrate on the warning generation aspect. The loop is closed.

Your Answer

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

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