emacs-devel
[Top][All Lists]
Advanced

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

Re: eval-when-compile


From: Pascal J. Bourguignon
Subject: Re: eval-when-compile
Date: Fri, 27 Jul 2012 08:26:40 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.4 (gnu/linux)

Achim Gratz <address@hidden> writes:

> [I hope this is the correct list for asking this question.]
>
> I've been trying to use eval-when-compile to switch between alternate
> versions of code based on a compile-time decision.  However it seems
> that either I don't understand the documentation or something doesn't
> quite work.
>
> Compiling this source file:
>
> (eval-when-compile
>   (if t
>       (defvar unquoted-t "true")
>     (defvar unquoted-nil "false")))
> (eval-when-compile
>   (if nil
>       '(defvar quoted-t "true")
>     '(defvar quoted-nil "false")))

C-h f eval-when-compile RET

    Like `progn', but evaluates the body at compile time if you're compiling.
    Thus, the result of the body appears to the compiler as a quoted constant.
    In interpreted code, this is entirely equivalent to `progn'.

What more can I add?


The above source will evaluate, when you compile the file:

    (defvar unquoted-t "true")
    '(defvar quoted-nil "false")

When you load the file, it won't evaluate anything.

So what you've done is to define inside the compiler a variable named
unquoted-t, and nothing else.  Once the compiler exits, there remains
nothing of that variable.


> results in an empty (except the header of course) byte-compiled file.  I
> expected the quoted version to compile
> `(defvar quoted-nil "false")´

Why?  You never evaluated it, even at compilation time, much less at
load time!



> which is what that form evaluates to.  When I wrap a defmacro around it
> and call that macro outside the eval-when-compile:
>
> (eval-when-compile
>   (defmacro ewc-macro (&rest body)
>     (if nil
>       '(defvar macro-t "true")
>       '(defvar macro-nil "false"))))
> (ewc-macro)

Here, you're defining a macro at compilation time.  When compiling this
file, the macro is known and (ewc-macro) expands to (defvar macro-nil
"false") so that's compiled into the elc file, and that's the only thing
that's loaded.

If you try to load the .el file directly, then the macro is not defined,
and you're trying to call a function named (ewc-macro) which will fail.


> then I get the expected output in the byte-compiled file, but it seems
> there must be an easier way to do that.  The eval-when-compile in this
> version suppresses the macro definition itself being byte-compiled of
> course.

It's bad to restrict yourself to compilation-time.  One can also load
the sources directly (it's considered "run-time").

If you put this:

    (require 'cl)
    (eval-when (compile) (print '(hi compile)))
    (eval-when (load)    (print '(hi load)))
    (eval-when (eval)    (print '(hi run)))

in a file named /tmp/time.el and then evaluate the following forms, the
messages appear in *Messages*:


    (byte-compile-file "/tmp/time.el")

    (hi compile)
    t


    (load "/tmp/time.elc")

    (hi load)
    t


    (load "/tmp/time.el")

    (hi run)
    t

So, while it's conceivable to have a big program loaded into the
compiler that you don't want to load at run-time (eg. you're writing a
compiler for a different language, load it, and then compile a program
in this language thru a macro, and you want just the resulting lisp code
of this compilation to be included in the .elc), but in general, you
want to have access to the macros also at run-time (for interactive
use).

Now indeed, if you have decisions to make at compilation time, you need
to define variables and functions at compilation time to compute those
decisions.

    (eval-when-compile ; or (require 'cl) (eval-when (compile) …
      (defun decide-what-to-generate ()
         …))

    (defmacro generate-alternative ()
      (if (decide-what-to-generate) ; called at compilation time.
         `(progn
             (defvar *first-option* 42)
             (defun use-first-option ()
               (do-something-with *first-option*)))
         `(progn
             (defvar *second-option* 'zz)
             (defun use-second-option ()
               (do-something-with *second-option*)))))

    (generate-alternative)


Now of course, the problem is that when you load this file,  you don't
know what you will get.  Will you get a function named use-first-option
or a function named use-second-option?  Doubt.  Depends on what happened
when you compiled that file…  So I think it's not a good idea to do that
kind of things.

    
-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.




reply via email to

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