* how to turn this Gnus function into a macro?
@ 2004-01-07 22:19 Ted Zlatanov
2004-01-07 22:55 ` Jesper Harder
2004-01-08 2:13 ` Katsumi Yamaoka
0 siblings, 2 replies; 12+ messages in thread
From: Ted Zlatanov @ 2004-01-07 22:19 UTC (permalink / raw)
I tried to make this function into a macro but failed. Any help will
be greatly appreciated. As it is it works, so it's not a big deal but
I'm curious what I missed. The Emacs docs on macros are pretty bad,
and my problem boiled down to being unable to (funcall) a macro by
name.
Thanks
Ted
(defun spam-fetch-field-fast (article field)
"Fetch a field quickly, using the internal gnus-data-list function"
(when (numberp article)
(let* ((header (assoc article (gnus-data-list nil)))
(data-header (if header (gnus-data-header header) nil)))
(cond
((equal field 'from)
(mail-header-from data-header))
((equal field 'message-id)
(mail-header-message-id data-header))
((equal field 'subject)
(mail-header-subject data-header))
((equal field 'references)
(mail-header-references data-header))
((equal field 'date)
(mail-header-date data-header))
((equal field 'xref)
(mail-header-xref data-header))
((equal field 'extra)
(mail-header-extra data-header))
(t
nil)))))
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: how to turn this Gnus function into a macro?
2004-01-07 22:19 how to turn this Gnus function into a macro? Ted Zlatanov
@ 2004-01-07 22:55 ` Jesper Harder
2004-01-08 0:09 ` Ted Zlatanov
2004-01-08 2:13 ` Katsumi Yamaoka
1 sibling, 1 reply; 12+ messages in thread
From: Jesper Harder @ 2004-01-07 22:55 UTC (permalink / raw)
Ted Zlatanov <tzz@lifelogs.com> writes:
> I tried to make this function into a macro but failed. Any help will
> be greatly appreciated.
Why do you want it as a macro? If it's just to save a function call,
then `inline' or `defsubst' is better.
> As it is it works, so it's not a big deal but I'm curious what I
> missed. The Emacs docs on macros are pretty bad, and my problem
> boiled down to being unable to (funcall) a macro by name.
Named macros cannot be funcalled. So you probably haven't missed
anything -- except that fact :-)
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: how to turn this Gnus function into a macro?
2004-01-07 22:55 ` Jesper Harder
@ 2004-01-08 0:09 ` Ted Zlatanov
2004-01-08 4:13 ` Jesper Harder
0 siblings, 1 reply; 12+ messages in thread
From: Ted Zlatanov @ 2004-01-08 0:09 UTC (permalink / raw)
On Wed, 07 Jan 2004, harder@ifa.au.dk wrote:
> Ted Zlatanov <tzz@lifelogs.com> writes:
>
>> I tried to make this function into a macro but failed. Any help
>> will be greatly appreciated.
>
> Why do you want it as a macro? If it's just to save a function
> call, then `inline' or `defsubst' is better.
Because it can be much simpler, in the form
;; field is 'from or 'message-id for instance
(eval (format "mail-header-%s" (symbol-name field)))
Only a few lines, and it could be used with anything as the field,
instead of the hard-coded field names I have now. It also seemed
like an interesting challenge, but I failed it pretty badly :)
> Named macros cannot be funcalled. So you probably haven't missed
> anything -- except that fact :-)
That's what I figured, too. Actually I also ran into this while
updating spam-check-BBDB and ended up including the expanded macro
calls that look up a name or address in the BBDB hashtable inside
spam.el.
Ted
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: how to turn this Gnus function into a macro?
2004-01-07 22:19 how to turn this Gnus function into a macro? Ted Zlatanov
2004-01-07 22:55 ` Jesper Harder
@ 2004-01-08 2:13 ` Katsumi Yamaoka
2004-01-08 3:28 ` Ted Zlatanov
1 sibling, 1 reply; 12+ messages in thread
From: Katsumi Yamaoka @ 2004-01-08 2:13 UTC (permalink / raw)
>>>>> In <4noetfo10c.fsf@collins.bwh.harvard.edu>
>>>>> Ted Zlatanov <tzz@lifelogs.com> wrote:
> I tried to make this function into a macro but failed.
How about it?
(defmacro spam-fetch-field-fast (article field)
"Fetch a field quickly, using the internal gnus-data-list function"
(let ((macro (cond ((eq field 'from) 'mail-header-from)
((eq field 'message-id) 'mail-header-message-id)
((eq field 'subject) 'mail-header-subject)
((eq field 'references) 'mail-header-references)
((eq field 'date) 'mail-header-date)
((eq field 'xref) 'mail-header-xref)
((eq field 'extra) 'mail-header-extra))))
(if macro
`(let ((article ,article))
(if (numberp article)
(let* ((header (assoc article (gnus-data-list nil)))
(data-header (if header (gnus-data-header header))))
(,macro data-header)))))))
(macroexpand '(spam-fetch-field-fast ART from))
=> (let ((article ART))
(if (numberp article)
(let* ((header (assoc article (gnus-data-list nil)))
(data-header (if header (gnus-data-header header))))
(mail-header-from data-header))))
If the arg `article' is always not a cons form (i.e., a number
or a symbol), it can be simplified as follows:
(defmacro spam-fetch-field-fast (article field)
"Fetch a field quickly, using the internal gnus-data-list function"
(let ((macro (cond ((eq field 'from) 'mail-header-from)
((eq field 'message-id) 'mail-header-message-id)
((eq field 'subject) 'mail-header-subject)
((eq field 'references) 'mail-header-references)
((eq field 'date) 'mail-header-date)
((eq field 'xref) 'mail-header-xref)
((eq field 'extra) 'mail-header-extra))))
(if macro
`(if (numberp ,article)
(let* ((header (assoc ,article (gnus-data-list nil)))
(data-header (if header (gnus-data-header header))))
(,macro data-header))))))
(macroexpand '(spam-fetch-field-fast ART from))
=> (if (numberp ART)
(let* ((header (assoc ART (gnus-data-list nil)))
(data-header (if header (gnus-data-header header))))
(mail-header-from data-header)))
--
Katsumi Yamaoka <yamaoka@jpl.org>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: how to turn this Gnus function into a macro?
2004-01-08 2:13 ` Katsumi Yamaoka
@ 2004-01-08 3:28 ` Ted Zlatanov
2004-01-08 3:33 ` Katsumi Yamaoka
2004-01-08 3:42 ` Jeremy Maitin-Shepard
0 siblings, 2 replies; 12+ messages in thread
From: Ted Zlatanov @ 2004-01-08 3:28 UTC (permalink / raw)
Cc: ding
On Thu, 08 Jan 2004, yamaoka@jpl.org wrote:
>>>>>> In <4noetfo10c.fsf@collins.bwh.harvard.edu>
>>>>>> Ted Zlatanov <tzz@lifelogs.com> wrote:
>
>> I tried to make this function into a macro but failed.
>
> How about it?
Your solution still has a special case for every field - I was hoping
that given ARTICLE and 'from as the arguments, the macro would
call (mail-header-from ARTICLE) for example.
If I could only funcall a macro, the code would be pretty simple:
;; pseudocode, doesn't work
(defun spam-fetch-field-fast (article field)
(when (and (numberp article) (symbolp field))
(funcall (intern (concat "mail-header-" (symbol-name field)))
(gnus-data-header (assoc article (gnus-data-list nil))))))
(it's not correct, but I think you see what I want to achieve)
Thanks!
Ted
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: how to turn this Gnus function into a macro?
2004-01-08 3:28 ` Ted Zlatanov
@ 2004-01-08 3:33 ` Katsumi Yamaoka
2004-01-08 3:42 ` Jeremy Maitin-Shepard
1 sibling, 0 replies; 12+ messages in thread
From: Katsumi Yamaoka @ 2004-01-08 3:33 UTC (permalink / raw)
>>>>> In <4n8ykjazla.fsf@collins.bwh.harvard.edu>
>>>>> Ted Zlatanov <tzz@lifelogs.com> wrote:
> Your solution still has a special case for every field - I was hoping
> that given ARTICLE and 'from as the arguments, the macro would
> call (mail-header-from ARTICLE) for example.
> If I could only funcall a macro, the code would be pretty simple:
> ;; pseudocode, doesn't work
> (defun spam-fetch-field-fast (article field)
> (when (and (numberp article) (symbolp field))
> (funcall (intern (concat "mail-header-" (symbol-name field)))
> (gnus-data-header (assoc article (gnus-data-list nil))))))
> (it's not correct, but I think you see what I want to achieve)
I see that `field' is also a variable. Sorry.
--
Katsumi Yamaoka <yamaoka@jpl.org>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: how to turn this Gnus function into a macro?
2004-01-08 3:28 ` Ted Zlatanov
2004-01-08 3:33 ` Katsumi Yamaoka
@ 2004-01-08 3:42 ` Jeremy Maitin-Shepard
2004-01-08 3:47 ` Katsumi Yamaoka
1 sibling, 1 reply; 12+ messages in thread
From: Jeremy Maitin-Shepard @ 2004-01-08 3:42 UTC (permalink / raw)
Cc: ding
Ted Zlatanov <tzz@lifelogs.com> writes:
> [snip]
> Your solution still has a special case for every field - I was hoping
> that given ARTICLE and 'from as the arguments, the macro would
> call (mail-header-from ARTICLE) for example.
> [snip]
This should do the trick:
(defmacro spam-fetch-field-fast (article field)
"Fetch a field quickly, using the internal gnus-data-list function"
(let ((macro (intern (concat "mail-header-" (symbol-name field)))))
(if macro
`(let ((article ,article))
(if (numberp article)
(let* ((header (assoc article (gnus-data-list nil)))
(data-header (if header (gnus-data-header header))))
(,macro data-header)))))))
--
Jeremy Maitin-Shepard
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: how to turn this Gnus function into a macro?
2004-01-08 3:42 ` Jeremy Maitin-Shepard
@ 2004-01-08 3:47 ` Katsumi Yamaoka
2004-01-08 4:06 ` Jeremy Maitin-Shepard
2004-01-08 6:06 ` Katsumi Yamaoka
0 siblings, 2 replies; 12+ messages in thread
From: Katsumi Yamaoka @ 2004-01-08 3:47 UTC (permalink / raw)
>>>>> In <87k743qf5t.fsf@jbms.ath.cx>
>>>>> Jeremy Maitin-Shepard <jbms@attbi.com> wrote:
> (defmacro spam-fetch-field-fast (article field)
> "Fetch a field quickly, using the internal gnus-data-list function"
> (let ((macro (intern (concat "mail-header-" (symbol-name field)))))
> (if macro
> `(let ((article ,article))
> (if (numberp article)
> (let* ((header (assoc article (gnus-data-list nil)))
> (data-header (if header (gnus-data-header header))))
> (,macro data-header)))))))
Unfortunately, it dosn't work for all `field's.
(macroexpand '(spam-fetch-field-fast ART FIELD))
=> (let ((article ART))
(if (numberp article)
(let* ((header (assoc article (gnus-data-list nil)))
(data-header (if header (gnus-data-header header))))
(mail-header-FIELD data-header))))
BTW, (eval '(MACRO ARG)) can be used, however it is four times
slower than (MACRO ARG).
--
Katsumi Yamaoka <yamaoka@jpl.org>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: how to turn this Gnus function into a macro?
2004-01-08 3:47 ` Katsumi Yamaoka
@ 2004-01-08 4:06 ` Jeremy Maitin-Shepard
2004-01-08 6:06 ` Katsumi Yamaoka
1 sibling, 0 replies; 12+ messages in thread
From: Jeremy Maitin-Shepard @ 2004-01-08 4:06 UTC (permalink / raw)
Katsumi Yamaoka <yamaoka@jpl.org> writes:
> [snip: macro-eval-time symbol interning example]
> Unfortunately, it dosn't work for all `field's.
> (macroexpand '(spam-fetch-field-fast ART FIELD))
> => (let ((article ART))
> (if (numberp article)
> (let* ((header (assoc article (gnus-data-list nil)))
> (data-header (if header (gnus-data-header header))))
> (mail-header-FIELD data-header))))
> BTW, (eval '(MACRO ARG)) can be used, however it is four times
> slower than (MACRO ARG).
Indeed, if the field cannot always be specified as a compile-time
constant symbol, this type of approach is simply not very useful.
Special casing via `cond', as in your example, is more appropriate.
--
Jeremy Maitin-Shepard
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: how to turn this Gnus function into a macro?
2004-01-08 0:09 ` Ted Zlatanov
@ 2004-01-08 4:13 ` Jesper Harder
0 siblings, 0 replies; 12+ messages in thread
From: Jesper Harder @ 2004-01-08 4:13 UTC (permalink / raw)
Ted Zlatanov <tzz@lifelogs.com> writes:
> On Wed, 07 Jan 2004, harder@ifa.au.dk wrote:
>
>> Why do you want it as a macro? If it's just to save a function
>> call, then `inline' or `defsubst' is better.
>
> Because it can be much simpler, in the form
>
> ;; field is 'from or 'message-id for instance
> (eval (format "mail-header-%s" (symbol-name field)))
>
> Only a few lines, and it could be used with anything as the field,
> instead of the hard-coded field names I have now.
Yeah, I see what you mean.
`mail-header-*' should really be defsubsts rather than macros, but
unfortunately the Emacs byte compiler isn't good enough to make them
as efficient (it should be possible for a sufficiently smart
compiler).
> It also seemed like an interesting challenge, but I failed it pretty
> badly :)
You can sometimes cheat and funcall a macro by wrapping a lambda
around it:
(funcall (lambda (x) (macro x)) y)
But if you think about when macro expansion happens, it's obvious that
it can only work in a few cases.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: how to turn this Gnus function into a macro?
2004-01-08 3:47 ` Katsumi Yamaoka
2004-01-08 4:06 ` Jeremy Maitin-Shepard
@ 2004-01-08 6:06 ` Katsumi Yamaoka
2004-01-08 20:30 ` Ted Zlatanov
1 sibling, 1 reply; 12+ messages in thread
From: Katsumi Yamaoka @ 2004-01-08 6:06 UTC (permalink / raw)
>>>>> In <b9ybrpf2jac.fsf@jpl.org> Katsumi Yamaoka wrote:
> BTW, (eval '(MACRO ARG)) can be used, however it is four times
> slower than (MACRO ARG).
Here are benchmarks:
;; The function which Ted posted first.
;; <4noetfo10c.fsf@collins.bwh.harvard.edu>
(byte-compile 'spam-fetch-field-fast)
(benchmark 1000 (spam-fetch-field-fast 51549 'from))
0.001971006393432617
0.0019199848175048828
0.001867055892944336
0.0019189119338989258
0.0018950700759887695
;; The `eval' version.
(defun spam-fetch-field-fast-1 (article field)
(when (and (numberp article) (symbolp field))
(eval `(,(intern (concat "mail-header-" (symbol-name field)))
,(gnus-data-header (assoc article (gnus-data-list nil)))))))
(byte-compile 'spam-fetch-field-fast-1)
(benchmark 1000 (spam-fetch-field-fast-1 51549 'from))
0.006534099578857422
0.006331086158752441
0.006301999092102051
0.006219029426574707
0.006276965141296387
--
Katsumi Yamaoka <yamaoka@jpl.org>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: how to turn this Gnus function into a macro?
2004-01-08 6:06 ` Katsumi Yamaoka
@ 2004-01-08 20:30 ` Ted Zlatanov
0 siblings, 0 replies; 12+ messages in thread
From: Ted Zlatanov @ 2004-01-08 20:30 UTC (permalink / raw)
Cc: ding
I think I'll keep the function form since it's significantly faster
than the macro, but seeing yours and Jeremy's solutions taught me lots
about macros - thanks! That will help me understand a lot of the Gnus
and Emacs internals.
Ted
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2004-01-08 20:30 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-01-07 22:19 how to turn this Gnus function into a macro? Ted Zlatanov
2004-01-07 22:55 ` Jesper Harder
2004-01-08 0:09 ` Ted Zlatanov
2004-01-08 4:13 ` Jesper Harder
2004-01-08 2:13 ` Katsumi Yamaoka
2004-01-08 3:28 ` Ted Zlatanov
2004-01-08 3:33 ` Katsumi Yamaoka
2004-01-08 3:42 ` Jeremy Maitin-Shepard
2004-01-08 3:47 ` Katsumi Yamaoka
2004-01-08 4:06 ` Jeremy Maitin-Shepard
2004-01-08 6:06 ` Katsumi Yamaoka
2004-01-08 20:30 ` Ted Zlatanov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).