Lisp HUG Maillist Archive

Overriding imported macro

Hi,

I’m curious: is there a way to ”extend” an imported macro?

Let’s say I have a package defining a macro:

(in-package :silly-macros)

(defmacro with-dynamic-var ((value) &body body)
  `(let ((*dynamic-var* ,value))
     ,@body))

Now, in the code that uses silly-macros, I would like to use with-dynamic-var, but I would also like to do something more (like binding another dynamic variable).

Obviously I could define a new macro and call with-dynamic-var in its definition, but what I really would like to do is to have a new macro with extended behavior *using the same name*, overriding or shadowing the old.

Is this possible?

Erik



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

Re: Overriding imported macro



On 15 May 2020, at 23:32, Erik Ronström <erik.ronstrom@doremir.com> wrote:

Hi,

I’m curious: is there a way to ”extend” an imported macro?

Let’s say I have a package defining a macro:

(in-package :silly-macros)

(defmacro with-dynamic-var ((value) &body body)
 `(let ((*dynamic-var* ,value))
    ,@body))

Now, in the code that uses silly-macros, I would like to use with-dynamic-var, but I would also like to do something more (like binding another dynamic variable).

Obviously I could define a new macro and call with-dynamic-var in its definition, but what I really would like to do is to have a new macro with extended behavior *using the same name*, overriding or shadowing the old.

Is this possible?


If you don’t want to edit the sources of silly-macros, or your sources at all, then the best solution remaining is to set a *macroexpansion-hook*.

Other kludges would be to put reader macros, for example on #\( to substitute your with-dynamic-var).


-- 
__Pascal J. Bourguignon__




Re: Overriding imported macro

Erik Ronström <erik.ronstrom@doremir.com> writes:

> I’m curious: is there a way to ”extend” an imported macro?
>
> Let’s say I have a package defining a macro:
>
> (in-package :silly-macros)
>
> (defmacro with-dynamic-var ((value) &body body)
>   `(let ((*dynamic-var* ,value))
>      ,@body))
>
> Now, in the code that uses silly-macros, I would like to use with-dynamic-var, but I would also like to do something more (like binding another dynamic variable).
>
> Obviously I could define a new macro and call with-dynamic-var in its definition, but what I really would like to do is to have a new macro with extended behavior *using the same name*, overriding or shadowing the old.
>
> Is this possible?

It can be done with *MACROEXPAND-HOOK* but it's usually a bad idea.

-- 
Laat hulle almal sterf.  Ek is tevrede om die wêreld te sien brand en die vallende 
konings te spot.  Ek en my aasdier sal loop op die as van die verwoeste aarde.

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

Re: Overriding imported macro



On 16 May 2020, at 00:07, Lieven Marchand <mal@wyrd.be> wrote:

Erik Ronström <erik.ronstrom@doremir.com> writes:

I’m curious: is there a way to ”extend” an imported macro?

Let’s say I have a package defining a macro:

(in-package :silly-macros)

(defmacro with-dynamic-var ((value) &body body)
 `(let ((*dynamic-var* ,value))
    ,@body))

Now, in the code that uses silly-macros, I would like to use with-dynamic-var, but I would also like to do something more (like binding another dynamic variable).

Obviously I could define a new macro and call with-dynamic-var in its definition, but what I really would like to do is to have a new macro with extended behavior *using the same name*, overriding or shadowing the old.

Is this possible?

It can be done with *MACROEXPAND-HOOK* but it's usually a bad idea.

What you would expect, is to have hooks provided by the with-dynamic-var macro to change its behaviour in a controlled way.  In the absence of such macro-specific hooks, using the generic and global *macroexpand-hook* should be acceptable.  As long as you keep the semantics of the with-dynamic-var macro, you can implement extensions in the *macroexpand-hook*.  



(defmacro with-dynamic-var ((value) &body body)
 `(let ((*dynamic-var* ,value))
    ,@body))

(defvar *dynvar-level* 0)

(defun make-dynamic-var-hook (old-hook)
  (lambda (expander form env)
    (if (and (listp form)
             (eq 'with-dynamic-var (first form)))
        `(let ((*dynvar-level* (1+ *dynvar-level*)))
           ,(funcall expander form env))
        (funcall old-hook expander form env))))


(setf *macroexpand-hook* (make-dynamic-var-hook *macroexpand-hook*))
(with-dynamic-var (42) (list *dynvar-level* *dynamic-var*))
--> (1 42)



-- 
__Pascal J. Bourguignon__




Re: Overriding imported macro

Hi Erik,

that's a somewhat advanced and obscure feature.

LispWorks has a built-in feature for that, which in Lisp is usually called advising.
This usually adds code to a function.

LispWorks DEFADVICE can also add code to macros: before, after and around.
It might work for your purpose...

Note that LispWorks' DEFADVICE is an extension to Common Lisp.


The basic macro:

(defparameter *dynamic-var-0* 'foo-0)

(defmacro with-dynamic-var ((value) &body body)
  `(let ((*dynamic-var-0* ,value))
     ,@body))


Advising a macro:

Now we want to add another level of LET binding for a different variable around it:

(defparameter *dynamic-var-1* 'foo-1)

(defadvice (with-dynamic-var around-with-dynamic-var :around)
    (call-form env)
  (destructuring-bind (with-dynamic-var-symbol (value) &body body)
      call-form
    (declare (ignore with-dynamic-var-symbol body))
    `(let ((*dynamic-var-1* (1+ ,value)))
       ,(call-next-advice call-form env))))


The lambda list is call-form and env, which means we need to destructure it.
CALL-NEXT-ADVICE then calls the next macro implementation.

Example use:

(defun test (bar)
  (with-dynamic-var (bar)
    (list :var-0 *dynamic-var-0*
          :var-1 *dynamic-var-1*)))


Regards,
Rainer



Am 15.05.2020 um 23:32 schrieb Erik Ronström <erik.ronstrom@doremir.com>:

Hi,

I’m curious: is there a way to ”extend” an imported macro?

Let’s say I have a package defining a macro:

(in-package :silly-macros)

(defmacro with-dynamic-var ((value) &body body)
 `(let ((*dynamic-var* ,value))
    ,@body))

Now, in the code that uses silly-macros, I would like to use with-dynamic-var, but I would also like to do something more (like binding another dynamic variable).

Obviously I could define a new macro and call with-dynamic-var in its definition, but what I really would like to do is to have a new macro with extended behavior *using the same name*, overriding or shadowing the old.

Is this possible?

Erik



_______________________________________________
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:28 UTC