Lisp HUG Maillist Archive

Using with-slots in a macro

Is this generally considered bad form and will break macros (akin to the reason gensym exists)?

What's the typical way to handle this? Just always use accessor functions for slots?

Just in case the above isn't clear enough... here's an example:

(defstruct foo bar)

(defmacro dummy-macro ((sym value) &body body)
  `(let ((,sym ,value))
     (with-slots (bar)
         ,sym
       (progn #| do something with bar |# ,@body))))

Now I end up using it like so:

(let ((bar ...))
  (dummy-macro (k v) #| do something with bar |#))

I'm pretty much borked here, right?

Follow-up question:

Is the above "okay" assuming that the macro exists in one package and the use of the macro exists in another package? In that case, the with-slots would actually be referencing my-package::bar and the usage code would be using cl-user::bar (as an example). Is it still bad form, though?

Jeff M.

Re: Using with-slots in a macro

On 18 Mar 2013, at 20:31, Jeff Massung wrote:

> Is this generally considered bad form and will break macros (akin to the reason gensym exists)?
> 
> What's the typical way to handle this? Just always use accessor functions for slots?
> 
> Just in case the above isn't clear enough... here's an example:
> 
> (defstruct foo bar)
> 
> (defmacro dummy-macro ((sym value) &body body)
>   `(let ((,sym ,value))
>      (with-slots (bar)
>          ,sym
>        (progn #| do something with bar |# ,@body))))
> 
Yes, this will mean that BAR has special meaning inside the body, which you probably do not want.  However WITH-SLOTS deals with this: you can specify a name for the thing bound to the slot, so you could do something like this:

(defmacro with-bog ((s v) &body forms)
  (let ((barn (make-symbol "BAR")))
    `(let ((,s ,v))
       (with-slots ((,barn bar)) sym
         ... do something with ,barn ...
         ,@body))))

(I use <foo>n to mean "name for <foo>" which has come out unfortunately here.

However in this case why can't you just do:

(defmacro with-bog ((s v) &body forms)
  `(let ((,s ,v))
     (with-slots (bar) ,sym
       ... do somthing with bar ...)
     ,@forms))

?

> 
> Is the above "okay" assuming that the macro exists in one package and the use of the macro exists in another package? In that case, the with-slots would actually be referencing my-package::bar and the usage code would be using cl-user::bar (as an example). Is it still bad form, though?

Yes, it's an accident waiting to happen.


_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html


Re: Using with-slots in a macro

Jeff Massung <massung@gmail.com> writes:

> Is this generally considered bad form and will break macros (akin to
> the reason gensym exists)?
>
> What's the typical way to handle this? Just always use accessor
> functions for slots?
>
> Just in case the above isn't clear enough... here's an example:
>
> (defstruct foo bar)
>
> (defmacro dummy-macro ((sym value) &body body)
>   `(let ((,sym ,value))
>      (with-slots (bar)
>          ,sym
>        (progn #| do something with bar |# ,@body))))
>
> Now I end up using it like so:
>
> (let ((bar ...))
>   (dummy-macro (k v) #| do something with bar |#))
>
> I'm pretty much borked here, right?
>
> Follow-up question:
>
> Is the above "okay" assuming that the macro exists in one package and
> the use of the macro exists in another package? In that case, the
> with-slots would actually be referencing my-package::bar and the
> usage code would be using cl-user::bar (as an example). Is it still
> bad form, though?

There are a lot of languages providing scoping operators that will
deliver symbols in scopes without mentionning them.  For example, pascal
'with'.

So it depends on the language you want to build.
You mention "do something with bar" inside the macro, but the body could
also want to do something with bar.  In which case what you mention
about packages would be a reason why to avoid this exact form.  As Tim
mentionned, let the user specify a symbol to bind to the slot (or use
your own gensym if it must be hidden from the body).  Only if you're
designing a DSL where you can restrict the package dealing from the
user, you can 'import' in scopes implicit symbols.  But even in this
case, you may want not to, since this would prevent embedding one
occurence of the macro in the body of another having access to both
slots.  When you let the user name the symbols, it's easy:

    (with-slots ((bar1 bar)) object1
      (with-slots (bar2 bar)) object2
         (+ bar1 bar2))

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html


Updated at: 2020-12-10 08:35 UTC