Xaving
Xaving

Reputation: 319

How to use a parameter in a macro call?

I have defined the following simple macro:

 (defmacro define-class (class-name)
  `(defclass ,class-name ()()))

And now I want to use it in the following function:

(defun create-data (mode)
  (define-class mode))

After compiling the last function I get the following message, the variable MODE is defined but never used.

And when I execute the function to create a class "myclass", I get instead the creation of a class of type "mode":

 (create-data 'myclass)
 #<STANDARD-CLASS MODE>

Seems that my argument is not used? How can I get the function create-data to use the argument?

Upvotes: 1

Views: 151

Answers (2)

Rainer Joswig
Rainer Joswig

Reputation: 139411

I would use something like this:

CL-USER 86 >  (defmacro define-class (class-name)
                `(defclass ,class-name ()()))
DEFINE-CLASS

CL-USER 87 > (defun create-data (mode)
               (funcall (compile nil `(lambda ()
                                        (define-class ,mode)))))
CREATE-DATA

CL-USER 88 > (create-data 'bar)
#<STANDARD-CLASS BAR 402016CC73>

Above uses code generation and the built-in compiler.

Upvotes: 2

Sylwester
Sylwester

Reputation: 48775

defclass isn't a function but a macro. It uses the name provided in the source (mode in your case) and it's not the same as your variable mode. In fact some CL implementations would warn you that argument mode is never used.

You can macroexpand it (macroexpand '(defclass mode ()())) to check what it becomes in your implementation. I get this in CLISP (I've cleaned it up a little):

(progn
  (eval-when (compile load eval)
    (apply #'ensure-class 
           'mode ; notice mode is quoted
           :direct-superclasses (list) 
           :direct-slots (list) 
           :metaclass clos::<standard-class>
           (append '(:fixed-slot-locations nil) 
                    (list :direct-default-initargs nil 
                          :documentation nil 
                          :generic-accessors 't))))
  (find-class 'mode)) ; notice mode is quoted

The expansion is imlementation dependent but the result is the same in all. mode is the name of the class being defined and not what you pass as argument.

You should use (define-class myclass) instead of (create-data 'myclass).

Upvotes: 3

Related Questions