0
votes

I encounter errors when passing an object argument to a macro. Must I quote the argument, put it in a list, or not quote it?

I wish to use Clozure Common Lisp to generate and run multiple processes in parallel using a read-write-lock to control data output to another process. With-write-lock is a macro that waits until the given lock is available for write access, then executes its body with the lock held. However, I get errors no matter how I try to pass the lock to with-write-lock. I'm having trouble I think because I fail to understand how to pass a lock object to the with-write-lock macro. If I bind the lock to a symbol I get destructuring errors:

(let ((l (make-read-write-lock)))
  (with-write-lock l (1+ 1)))
==>
> Error: L can't be destructured against the lambda list (LOCK), because it is not a proper list.

While executing: (:INTERNAL CCL::NX1-COMPILE-LAMBDA), in process Listener(4).

but if I pass the call to make-read-write-lock as the lock argument to with-write-lock then I get an undeclared free variable error:

(with-write-lock (make-read-write-lock) (1+ 1))
==>
;Compiler warnings for "/Users/frank/Documents/Lisp/threaded/act-parallel.lisp" :
;In an anonymous lambda form at position 18: Undeclared free variable MAKE-READ-WRITE-LOCK

Error: Unbound variable: MAKE-READ-WRITE-LOCK While executing: #, in process Listener(4).

Am I failing because I misunderstand how to pass an object to a macro or am I going awry because or something more particular to with-write-lock?

Here's the with-write-lock macro that comes with Clozure Common Lisp (macros.lisp):

(defmacro with-write-lock ((lock) &body body)
  (let* ((locked (gensym))
         (p (gensym)))
    `(with-lock-context
       (let* ((,locked (make-lock-acquisition))
              (,p ,lock))
         (declare (dynamic-extent ,locked))
         (unwind-protect
              (progn
                (write-lock-rwlock ,p ,locked)
                ,@body)
           (when (lock-acquisition.status ,locked) (unlock-rwlock ,p)))))))
1

1 Answers

3
votes

The lambda list for that macro is destructuring its arguments.

 ((lock) &body body)

Means that it wants the first argument as a list which contains the lock and then the body form. This is a pretty standard macro argument list in CL, you can use it like this:

(with-write-lock (lock)
  ..... body forms ....)

So your examples would be

(let ((l (make-read-write-lock)))
   (with-write-lock (l) (1+ 1)))

And:

(with-write-lock ((make-read-write-lock)) (1+ 1))

respectively. Note the extra parens around the first argument. For similar macros see with-open-file or destructuring-bind

(with-open-file ("path/to/file" :open :args)
  .... body ...)

(destructuring-bind (one two three) '(1 2 3)
  .... body forms ...)