Skip to content

eval-after-load を少し改造 (その2)

2012/06/10

仕様変更は少ないほうがいいよね、と言っておきながら早速仕様変更のお話です。

以前書いた `eval-after-load-q’ にはいくつかの狙いがありました。

  1. `eval-after-load’ の記述のしにくさを改善する。
  2. ファイル名の記述を `require’ のようにクオートしたシンボルで記述できるようにする。
  3. バイトコンパイルを行う。

この内1、2は糖衣構文を提供するもの(2に関してはわがまま成分多め)で、3は最適化に関するものと、異なる意図のコードが同居していました。

今回、emacs lisp にもコンパイラマクロを定義できること知り、また、次回示すユーティリティマクロを用意することで `eval-after-load’ を直接記述する必要がなくなったので、次のように書き直しました。

(eval-when-compile
  (require 'cl))

(defalias 'eval-after-load-compile 'eval-after-load)

(define-compiler-macro eval-after-load-compile (file form)
  (if (eq 'quote (car form))
      `(eval-after-load ,file
         '(funcall
           ,(byte-compile
             `(lambda ()
                ,(cadr form)))))
    `(eval-after-load ,file ,form)))

(defmacro eval-after-load-q (file &rest form)
  (declare (indent 1))
  `(eval-after-load-compile ,file
                            '(progn ,@form)))

eval-after-load-compile

`eval-after-load’は Emacs の標準関数なので、バイトコンパイルするかどうかを明示的にして他所に影響が出ないようにするためと、展開結果に展開前と同じ関数を含めたいので `eval-after-load-compile’ というエイリアスを用意して、もとの `eval-after-load’ と区別をします。
`eval-after-load-compile’ はクオートされたフォームが与えられた場合だけバイトコンパイル時にフォームをバイトコンパイルします。
それ以外の時は `eval-after-load’ と同じ動作をします。

ELISP> (compiler-macroexpand
        '(eval-after-load-compile "hoge"
                                  '(+ 1 2 3)))
(eval-after-load "hoge"
  '(funcall
    #[nil "\300\207"
          [6]
          1]))

ELISP> (compiler-macroexpand
        '(eval-after-load-compile "hoge"
                                  (list '+ 1 2 3)))
(eval-after-load "hoge"
  (list '+ 1 2 3))

eval-after-load-q

`eval-after-load-q’ に関しては、クオートと `progn’ を省略するだけにとどめ、 `eval-after-load-compile’ を呼ぶようになっています。
コンパイルの必要性を感じない場合は `eval-after-load’ に書き換えるといいと思います。

ELISP> (macroexpand '(eval-after-load-q "hoge"
                       (message "hello ")
                       (message "world")))
(eval-after-load-compile "hoge"
                         '(progn
                            (message "hello ")
                            (message "world")))

おわりに

というわけで、またまた `eval-after-load’ に関する話でした。
実際のところ `eval-after-load’ の中で関数でも定義しない限りバイトコンパイルによる最適化の恩恵はほとんど無いのではないかと思われます。
それでも僕がバイトコンパイルを行いたいのは、バイトコンパイル時に不正な式を見つけだせるようにしたいからです。
本当はそういう仕組みが用意されているのかもしれませんが、とりあえずこれで怪しい式に対して警告が出るようになりました。

これで、.emacs のロード中にコケるという悲しい事態をいくらか回避できるのではないでしょうか。

広告

From → Emacs

コメントする

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。