all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* RFC: `macro-eval'
@ 2006-08-30 17:11 Stuart D. Herring
  2006-08-31  7:33 ` Richard Stallman
  0 siblings, 1 reply; 4+ messages in thread
From: Stuart D. Herring @ 2006-08-30 17:11 UTC (permalink / raw)


I wrote a macro to automatically generate the boilerplate "delayed
evaluation with uninterned symbol" code needed in many macros (and
described at (elisp)Surprising Local Vars), which I present for comment. 
As far as my testing shows, it works both in interpreted and compiled
environments, with the one caveat that, as it uses `progv', it both
requires the cl library at runtime and generates spurious warnings upon
compilation because the byte compiler doesn't recognize that `progv' binds
variables.  (This of course is not easily fixed, since `progv' can
calculate the lists of variables to bind at runtime!)

(put 'macro-eval 'lisp-indent-function 1)
(defmacro macro-eval (spec &rest body)
  "Eval BODY with symbols in SPEC bound to temporary symbols.
For use in macros.  Each element of SPEC looks like VAR or (VAR VAL).  At
reevaluation time, each symbol will be bound to the evaluated form of the
corresponding VAL, or to the evaluated form of VAR's value if no VAL.
Note that evaluation and binding occurs like `let' and not `let*'."
  (let* ((vars (mapcar (lambda (e) (or (car-safe e) e)) spec))
         (vals (mapcar (lambda (e) (if (consp e) `',(cadr e) e)) spec))
         (syms (mapcar 'gensym (mapcar 'symbol-name vars)))
         (comma '\,))
    (list '\` `(progv ',syms
                   (mapcar 'eval ',(list comma `(mapcar 'eval ',vals)))
                 ,(list comma `(progv ',vars ',syms ,@body))))))


With this, it becomes possible to write the example `for' macro thusly:

(defmacro inc (var) `(setq ,var (1+ ,var)))

(defmacro for (var from init to final do &rest body)
  "Execute a simple for loop: (for i from 1 to 10 do (print i))."
  ;; We evaluate init this way to provide the correct evaluation order.
  (macro-eval (init final)
    `(let ((,var ,init))
       (while (<= ,var ,final)
         ,@body
         (inc ,var)))))

The savings in code are more pronounced when the macro does not bind
client variables, as often the `let's can be discarded entirely.

I'm quite willing to believe there are better ways of achieving this;
improvements and suggestions are welcome.  (For instance, is it possible
to do without the `comma' variable?)  If it seems useful, I can also
implement a `progv'-like macro that requires static variable selection so
the compiler might be happier.  (Of course, let me know if that already
exists!)

Davis

-- 
This product is sold by volume, not by mass.  If it appears too dense or
too sparse, it is because mass-energy conversion has occurred during
shipping.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: RFC: `macro-eval'
  2006-08-30 17:11 RFC: `macro-eval' Stuart D. Herring
@ 2006-08-31  7:33 ` Richard Stallman
  2006-08-31  7:47   ` David Kastrup
  0 siblings, 1 reply; 4+ messages in thread
From: Richard Stallman @ 2006-08-31  7:33 UTC (permalink / raw)
  Cc: emacs-devel

    I wrote a macro to automatically generate the boilerplate "delayed
    evaluation with uninterned symbol" code needed in many macros (and
    described at (elisp)Surprising Local Vars), which I present for comment. 

Actually we recently decided to stop using that method for two
important macros, dotimes and dolist, because it turns out to be
rather wasteful to generate all those symbols.  We concluded that it
is better, overall, to use an interned symbol so that only one symbol
would be needed.  We gave the interned symbol a name that users will
tend not to use.

Maybe that means we should change the recommendations in the Lisp
Manual.  However, for other macros that are used less often, the
recommendation there may still be best.

In many other Lisp implementations the compiler would get rid of such
variables, so the recommended technique costs nothing.  But the Emacs
Lisp byte compiler can't do that, because Emacs bytecode has no
anonymous stack slots.

    As far as my testing shows, it works both in interpreted and compiled
    environments, with the one caveat that, as it uses `progv', it both
    requires the cl library at runtime

That is a fatal flaw for this implementation.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: RFC: `macro-eval'
  2006-08-31  7:33 ` Richard Stallman
@ 2006-08-31  7:47   ` David Kastrup
  2006-08-31 22:57     ` Richard Stallman
  0 siblings, 1 reply; 4+ messages in thread
From: David Kastrup @ 2006-08-31  7:47 UTC (permalink / raw)


Richard Stallman <rms@gnu.org> writes:

> In many other Lisp implementations the compiler would get rid of
> such [uninterned] variables, so the recommended technique costs
> nothing.  But the Emacs Lisp byte compiler can't do that, because
> Emacs bytecode has no anonymous stack slots.

Just for curiosity: would that be different with the lexical-let
branch?

-- 
David Kastrup, Kriemhildstr. 15, 44793 Bochum

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: RFC: `macro-eval'
  2006-08-31  7:47   ` David Kastrup
@ 2006-08-31 22:57     ` Richard Stallman
  0 siblings, 0 replies; 4+ messages in thread
From: Richard Stallman @ 2006-08-31 22:57 UTC (permalink / raw)
  Cc: emacs-devel

    Just for curiosity: would that be different with the lexical-let
    branch?

I don't know.  I don't remember how that is implemented.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2006-08-31 22:57 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-08-30 17:11 RFC: `macro-eval' Stuart D. Herring
2006-08-31  7:33 ` Richard Stallman
2006-08-31  7:47   ` David Kastrup
2006-08-31 22:57     ` Richard Stallman

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.