3
votes

SBCL generates spurious style warnings about undefined functions. (The functions are defined, just later in the file.) I want to solve this problem once and for all. Fortunately, there is a way to do this:

(declaim (sb-ext:muffle-conditions style-warning))

The downside is that CCL, for obvious reasons, barfs on a program containing the above. I try to solve this problem with a conditional:

(#+sbcl (declaim (sb-ext:muffle-conditions style-warning)))

but now SBCL is unhappy: "illegal function call".

How do you put such a declaim into a portable program?

2

2 Answers

7
votes

Note that while the existing answer is right, disabling warnings is not a good practice. In your case, it is probably not necessary.

Common Lisp has a notion of compilation unit, where multiple definitions are grouped together. This gives a chance for the compiler/interpreter to take care of cross-references among functions (an interpreter could collect warnings and keep only those that are not found later, for example).

For example, in file #P"/tmp/foo.pl":

(defun mut-rec-foo (x)
  (when (plusp x)
    (mut-rec-bar (1- x))))

(defun mut-rec-bar (x)
  (print x)
  (mut-rec-foo (1- x)))

Do not evaluate anything in the file; instead do:

(compile-file #P"/tmp/foo.pl")

; compiling (DEFUN MUT-REC-FOO ...)
; compiling (DEFUN MUT-REC-BAR ...)

; /tmp/foo.fasl written
; compilation finished in 0:00:00.002

No warning. You can then call (load #P"/tmp/foo.fasl") to have the definitions in your current lisp environment, without warnings. Typically, ASDF and by extension Quicklisp use COMPILE-FILE, so your problem should disappear as soon as you bundle your files into a system.

You can also do:

(with-compilation-unit ()
  (defun mut-rec-foo/bis (x)
    (when (plusp x)
      (mut-rec-bar/bis (1- x))))

  (defun mut-rec-bar/bis (x)
    (print x)
    (mut-rec-foo/bis (1- x))))

Evaluating the whole block shows no warning for *EVALUATOR-MODE* being both :COMPILE or :INTERPRET.

What you witnessed happens when you evaluate each expression one after the other (or maybe one region after another one). There, the compiler has no way to know that the function already exists. Silencing the warning is the worse option, because you might actually have made an error.

If you know in advance that a function will exist, but not in your compilation unit (maybe it is only defined at runtime), the you can declaim that fact, as follows:

(declaim (ftype function my-function))

The above says that my-function must be assumed to be fbound to an object of type function. You could also give more information by refining what kind of function you claim it to be:

(declaim (ftype (function (number) (values string &optional)) num-to-string))

... for a function that accepts a number and returns exactly one value, a string.

(declaim (ftype (function () nil) forever-loop))

... for a function that accepts nothing and never return a value (loop or signals an error).

6
votes

Omit the outer pair of parentheses:

#+sbcl (declaim (sb-ext:muffle-conditions style-warning))

As you are using declaim, I assume, that the declaration appears at the top-level of a compilation unit. If you need to group multiple top-level statements, you can wrap them all with a progn (which doesn't change the "top-level"-ness).

The reason SBCL did complain is, that its reader reads

((declaim (sb-ext:muffle-conditions style-warning)))

(as the :SBCL feature is present), which is simply a syntax error. CCL does not complain, because its reader reads

()

which is simply another way to spell nil.