eval-when-compileとeval-and-compileの違い
Emacs lisp コンパイラの気持ちになるとわかります。
eval-when-compile
とeval-and-compile
似た名前のマクロだが、どういう動作をして、何が違うのかメモ。
定義
eval-when-conpile: https://github.com/emacs-mirror/emacs/blob/29a7d73d195761e8309a4fe23872888758436d1e/lisp/emacs-lisp/byte-run.el#L472
eval-and-compile: https://github.com/emacs-mirror/emacs/blob/29a7d73d195761e8309a4fe23872888758436d1e/lisp/emacs-lisp/byte-run.el#L482
なんとびっくり、全く同じ定義。動作はprogn
とほぼ同じ。
なんだ違う名前だけど、動作同じなのか〜ってそんなわけはない。
正確に言うと、Emacs lispインタプリタでは全く同じに解釈されるが、Emacs lispバイトコードへのコンパイルで違いがある。
Emacs lispバイトコードコンパイラでの評価
上に示すように、byte-compile-initial-macro-environment
変数にはEmacs lispインタプリタでの動作とEmacs lispバイトコードコンパイラでの動作が違うマクロが書かれている。
Emacs lispバイトコードコンパイラは、基本的にelispを評価することはせず、ソースコードをバイトコードへ変換(コンパイル)する。
しかし、eval-when-compile
やeval-and-compile
で囲んだ式はコンパイル中に評価される。
そして2つには違いがある。
実はrequire
は、Emacs lispバイトコードコンパイラによってeval-and-compile
同等の処理がなされる(マニュアルより)。
実例
以下のようなeval-foo-compile.el
ファイルを用いて試す。
(eval-when-compile (princ "eval-when-compile\n")) (eval-and-compile (princ "eval-and-compile\n"))
コマンドラインから
する。
$ emacs --script eval-foo-compile.el eval-when-compile eval-and-compile $ emacs -batch -f batch-byte-compile eval-foo-compile.el eval-when-compile eval-and-compile $ emacs --script eval-foo-compile.elc eval-and-compile $
期待した通りの結果になっている。
バイトコードの中身
Emacs lispバイトコードファイルは、Javaなどとは違って、全部バイナリというわけでない。
出力されたバイトコードeval-foo-compile.elc
は以下のようになった。
;ELC^W^@^@^@ ;;; Compiled ;;; in Emacs version 26.2 ;;; with all optimizations. ;;; This file uses dynamic docstrings, first added in Emacs 19.29. ;;; This file does not contain utf-8 non-ASCII characters, ;;; and so can be loaded in Emacs versions earlier than 23. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (princ "eval-and-compile\n")
今回はバイナリ列が一切出てこなかった。eval-when-compile
で囲んだ式は出力ファイルに現れないことがわかる。
終わり
バイトコードって考え方自体あやふやだったので、きっちり調べられてよかった。
元のコードのインタプリタとバイトコードコンパイラ/インタプリタがある言語って他にあるんだろうか。
Emacs lispもWrite once, run anywhereな感じで、多分30億のデバイスで動くと思うんだけど、バイトコードファイルだけで配布とか全くないのは自由ソフトウェアの文化だからなんだろうか(?)。