[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Is it possible for a macro to expand to nothing?

From: Pascal J. Bourguignon
Subject: Re: Is it possible for a macro to expand to nothing?
Date: Mon, 23 Nov 2009 19:33:13 +0100
User-agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/22.3 (darwin)

Alan Mackenzie <address@hidden> writes:

> Drew Adams <address@hidden> wrote:
>>> That is, not to a call to a null defun, but truly to nothing:  i.e.,
>>> the ensuing code (as least, when byte compiled) will be identical  to
>>> what it would have been, had the macro invocation been omitted.
>>> I want something like this:
>>> (defmacro ifdef (condition &rest forms)
>>>   "If the compile time CONDITION is non-nil, dump the FORMS to the
>>> calling defun.  Otherwise do nothing."
>>>   ......)
>> Hi Alan,
>> I'm not sure what you mean.
> You might not be the only one.  ;-)
> I think I want to be able to do this:
>     (defun foo ()
>       (setq bar 1)
>       (ifdef baz (setq bar 2)))
> , and if baz is nil at compile time, this function should be identical to
>     (defun foo ()
>       (setq bar 1))
> .
>> But if you mean something like "insert nothing", then you can do that
>> by producing nil and then using ,@ inside a backquote. IOW, instead of
>> inserting nil, you splice it in, which means inserting nothing.
> That means I need to have "`,@" in the invoking defun, doesn't it?  Maybe
> that would work, even if it is ugly.

That wouldn't work, backquote is a quote.

We cannot produce a macro that returns nothing, because as mentionned,
lisp source is not text, but a data structure, and a macro is a
function that always return one form to be inserted in that data

However, you can return a form that has no side effect: nil or (progn)
are good candidates.  (I'd tend to favor (progn) as the nil code,
since it can be used easily to add forms to it: 
  (append '(progn) '((print 'hi)) '(42))
produces a valid form, while:
  (append 'nil '((print 'hi)) '(42))


 (defmacro ifdef (expr &rest body)
   `(progn ,@(and (eval expr) body)))

  (setf baz nil)
  (dolist (baz '(nil t))
     (print (macroexpand '(ifdef baz (setq bar 2)))))



  (progn (setq bar 2))

Notice that in the case of your example, when baz is nil, the meaning
is changed, since it would return the result of the form returned by
the ifdef macro, not that of the previous form.  You could write:

  (defun foo ()
     (prog1 (setq bar 1)
        (ifdef baz (setq bar 2))))

  (defun foo ()
     (setq bar 1)
     (ifdef baz (setq bar 2))

depending on what you want.

(You could also write a two-branch ifdef instead.

Notice that in the case of Common Lisp, there are read-time tests #+
and #-, and read-time evaluation #. that allow you to implement
something similar to C #ifdef:

'(progn #+baz 1 #-baz 2 #.(+ 1 2)) --> (progn 1 3) or (progn 2 3)

Unfortunately the emacs lisp reader is much more primitive...      

__Pascal Bourguignon__

reply via email to

[Prev in Thread] Current Thread [Next in Thread]