0

The following macro...

(defmacro compile-time-eval (&rest body)
    (eval (cons 'progn body)))

...allows for compile-time metaprogramming like this (a small contrived example) :

(compile-time-eval
 `(defun join-dirs (a b)
    (concat a
            ,(if (eq system-type 'windows-nt)
                 "\\"
               "/")
            b)))

Is something like compile-time-eval part of the standard library? (eval-when-compile comes close, but it quotes the result.)

If not, what's the recommended way to implement this example?

  • 1
    eval-when-compile must quote its expansion to avoid re-evaluation at runtime. Why's that a problem? – lunaryorn Aug 13 '15 at 18:27
  • I want the result of the body to be evaluated at runtime. (eval-and-compile '(defun tmpfn ())) won't define tmpfn. – ens Aug 13 '15 at 18:35
  • 1
    Naturally, because you're not actually writing a function definition here. You're writing a quoted list that just looks like one. Compare (eval-and-compile '(defun foo ()) with (eval-and-compile (defun foo ()). Note the absence of the explicit quote. – lunaryorn Aug 13 '15 at 18:42
  • Yes, I think I need that level of indirection. How would you implement my example in the style of (eval-and-compile (defun ...))? – ens Aug 13 '15 at 18:47
  • See my answer. Generating function definitions is rather unusual, I'd just call a special macro in the function body. But generally, I'd avoid macros if possible. – lunaryorn Aug 13 '15 at 18:52
7

Macros do not evaluate to a result, they evaluate to an expansion, which is a form that substitutes the macro at the place where it's written, the expansion site. The expansion itself is not evaluated by the compiler.

As such, you normally don't try to generate function definitions completely. Rather you'd write a macro to performs whatever expansion you'd like to have, and simply use that macro within a function body, i.e.

(defmacro my/path-separator ()
  (if (eq system-type 'windows-nt) "\\" "/"))

(defun join-dirs (a b)
  (concat a (my/path-separator) b))

But in this specific example, you should not use macros at all. Emacs' byte code is not actually OS- or architecture-specific, and thus you must not generate system-specific code during expansion. In other words, the path separator is not a compile time constant, it's a load time constant and should be computed at load time rather than at compile time.

Generally you should only use macros for syntax, but never for semantics.

And actually you'd just use (expand-file-name "b" "a") here :)

  • Thanks. Actually, all I care about is semantics – I want to shift some run-time computations to compile-time. What else should I use other than macros? – ens Aug 13 '15 at 19:11
  • @ens Just don't do that at all…. It's of no use and has no benefits. – lunaryorn Aug 13 '15 at 19:29
  • The first line is a bit ambiguous (right or wrong, depending on the reading). When evaluated, a sexp that is a list whose car is a macro is first expanded, and then the result of expansion is evaluated. Macro expansion (function macroexpand) just expands. – Drew Aug 13 '15 at 21:10
  • @Drew I've tried to clarify it. Better now? – lunaryorn Aug 14 '15 at 7:04
  • Very good - that will help readers more, I think. – Drew Aug 14 '15 at 14:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.