Search code examples
macroscommon-lispsbcl

Understanding the error 'Is a macro, not a function'


I have had this error a few times is a macro, not a function. but found it hard to replicate the cause.

I have since discovered that the reason why I see the error is because I define a macro in a file I use it. And I use the macro above the definition.

For example:

In sbcl, i created a function for interactive interrupt from a terminal.

(defun some-long-running-thread ()
  
  ...

  #+sbcl
  (sb-sys:interactive-interrupt ()
    (progn
      (color :red (princ "C-c was pressed")) ;; <-- my macro
      (uiop:quit))))

(defmacro color (color &body body)
  `(multiple-value-bind (col val)
     (cl-ansi-text:with-color (,color)
       (progn
         ,@body))
     (declare (ignore col))
     val))

What is actually happening behind the scenes whereby functions can be defined in any order but macros cannot?

Note: I often define macros in the same file I use them.


Solution

  • A macro does source transformations during compile time.

    Say, you want to use a macro foo in your source code.

    Say, your code first uses (foo 123). Here the compiler does not know what foo is. The compiler assumes that it is a function. Thus it creates code for a function call to a yet unknown function foo.

    Now you define a macro under the same name foo. This has effects:

    • the compiler has before assumed that foo is a function. Now you define it as a macro -> thus the warning.

    • the compiler has already compiled code with the foo operator, as a function call. -> it won't recompile it.

    Rules, when introducing macros

    a) define all macros before they are used in the source

    b) provide all functionality (functions, macros, ...) which are used by the macro, before the macro is used in the source.

    The macro definition will be needed by the file compiler, when it sees a usage in that file: the macro will be needed to macroexpand the code during compile time.

    Practical: compiling functions vs. macros in a file

    Define a macro first before the function which might use the macro.

    The file compiler (-> compile-file) treats function and macro definitions different:

    • a function definition will be compiled, but it will not be loaded into the compile time environment. Thus during file compilation of a file, by default any function defined will not be callable during compilation.

    • a macro definition will be compile and it will be loaded into the compile time environment. Thus a macro defined in a file, which is being compiled, can be expanded during compilation of that file.