Gnus development mailing list
 help / color / mirror / Atom feed
* 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).