12

How do I avoid byte-compiler warnings Unused lexical variable in functions defined using macros expanding to defun?

E.g., macro defun-rcirc-command in rcirc.el uses the target variable which is not used by several invocations.

In Common Lisp I can use the ignorable declaration: (declare (ignorable target)).

Bad solutions:

  • Add something like (setq target target) to all the users of defun-rcirc-command which do not use target: that requires modifying many macro invocations.

  • Prefixing the ignorable variable with an underscore - _target - does not help because _ means ignore, not ignorable, i.e., when it is used, I get variable '_target' not left unused.

3
  • 1
    Prefixing them with an underscore should do it.
    – politza
    Apr 16, 2015 at 19:24
  • 1
    @politza: _ means ignore, not ignorable
    – sds
    Apr 16, 2015 at 19:42
  • 1
    Do you want to modify the macro to solve the problem? You could probably just put a (ignore VAR) for every defun argument before the ,@body expansion which will probably silence the errors. Apr 16, 2015 at 21:32

2 Answers 2

15

The way I've done that so far is to add a call of the shape

(ignore <var>)

This function call will be optimized away, but before that the compiler will still count it as a use, so the "unused" warning won't be triggered.

-1

Looking at the code, it appears that target is not intended to be a global variable but passed to the created function when it is called. If that is the case, it is better to create it as a symbol local to the macro. A simple example of a macro that creates a function that accepts an argument and adds 10 to it:

(defmacro xxx (name)  
  ""
  (let ((target (make-symbol "target")))
  `(defun ,name (,target) (+ 10 ,target))))

Calling

(xxx hamster)

will result in a function named hamster that accepts one argument.

Then you can call

(hamster 5)

and it will return 15.

The trick is to create a new symbol that will act as the argument to the new function.

EDIT:

I have always seen that if you are referring to the generated symbol in the passed in body expression, you include the name in the call like:

(defmacro xxx (name t2 &rest body)  
  ""
  (let ((t2-arg (make-symbol "target")))
  `(defun ,name (&optional ,t2-arg) 
     (let ((,t2 (or ,t2-arg 10)))
       ,@body))))

Which then turns the calls into:

(xxx hamster target (+ target 20))

where

(hamster)

which returns 30 and

(hamster 20)

returns 40.

Admittedly, this always bugs me when I write macros this way until I look at the usage in which it appears a parameter is declared and later used.

1
  • 2
    The body of the function is passed to the macro and it must be able to refer to target. IOW, your excellent suggestion is not applicable in this specific case.
    – sds
    Apr 16, 2015 at 21:23

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.