Common Lispは、特別の変数に格納されるデータの型や、それらの変数や
関数がどのように使われるかについて特殊なヒントをコンパイラに
与えることを許す、複雑で強力な“宣言”メカニズムを含む。この
パッケージは、declare
やlocally
、proclaim
、
declaim
、the
といったすべてのCommon Lisp宣言フォームの
版を定義する。
Common Lisp宣言のほとんどは、現在はEmacs Lispでは有用ではない。
バイトコードシステムは型情報から利益を得る機会をほとんど
提供していないし、special
宣言は完全に動的スコープのLispでは
冗長だからである。しかし、いくつかの宣言はEmacs 19の最適化
バイトコンパイラが使われるときに意味がある。以前の非最適化
コンパイラでは、これらの宣言は実際には無視される。
この関数は、decl-specによって指定された“グローバル”宣言を
記録する。proclaim
は関数なので、decl-specは評価され、
したがって通常は引用符をつけるべきである。
このマクロはproclaim
に似ているが、decl-spec引数を
任意個数取ることと、引数は評価されず引用符はつけない点が異なる。
declaim
マクロはまた、実行時と同様にコンパイル時にも
登録されるように、宣言の周りに
(eval-when (compile load eval) ...)
を置く(このことはきわめて
重要である。宣言は通常、declaim
フォームを含むファイルの残りを
コンパイラが扱う方法に影響するように意図しているからである)。
このマクロは、関数や他のコード内で宣言するために使われる。Common Lisp
はさまざまな場所で、一般にLisp文法を通じて、関数本体やlet
本体、
その他のような多くの“暗黙のprogn
”の始まりで宣言を許す。現在
declare
によって理解される唯一の宣言はspecial
である。
このパッケージでは、locally
はprogn
と相違はない。
the
によって提供される型情報はこのパッケージでは無視される;
言い替えれば、(the type form)
はformと
同等である。最適化バイトコンパイラの将来の版はこの情報を
利用するかもしれない。
たとえば、mapcar
はリストと配列の両方にマップできる。
列がリストか配列か前もってわからない限り、コンパイラが
コンパイラがmapcar
をインラインループへ展開することは難しい。
(mapcar 'car (the vector foo))
に対して、将来のコンパイラは、
ループをインラインに展開するための十分な情報を持つかもしれない。
今のところ、Emacs Lispは上記のコードを(mapcar 'car foo)
と正確に
同等に扱う。
proclaim
やdeclaim
、declare
のそれぞれの
decl-specは、どんな種類の宣言かを言うシンボルで始まる
リストであるべきである。このパッケージは、現在はspecial
や
inline
、notinline
、optimize
、warn
宣言を
理解する(warn
宣言は標準Common Lispへの拡張である)。type
やftype
のような他のCommon Lisp宣言は無言で無視される。
special
Emacs Lispのすべての変数は(Common Lispの意味で)“スペシャル”
であるので、special
宣言は単なる助言である。それらは単に、
指定された変数は意図的に関数本体で束縛されずに参照されることを最適化
バイトコンパイラに告げる。コンパイラは通常、そのような参照に警告を
発するが、それは局所変数への参照の誤記である可能性があるためである。
宣言(declare (special var1 var2))
は最適化
コンパイラでは(defvar var1) (defvar var2)
と
同等であり、より古いコンパイラ(非局所参照を警告しない)ではまったく
何とも同等ではない。
トップレベルコンテキストでは、(declaim (special var))
より
も(defvar var)
と書く方が一般に優れている。defvar
は
あなたの意図をより明らかにするからである。しかし古いバイトコンパイラは、
関数の内部に現れるdefvar
を扱えないが、
(declare (special var))
はすべてのコンパイラで正しく
働くよう注意が払われる。
inline
inline
decl-specは、コンパイラが準備できるときはいつでも、
その本体を呼び出す関数に“インライン”に展開すべき1つまたはそれ以上の
関数をリストする。たとえば、Common Lisp関数cadr
は、1回の
(比較的高価な)関数呼び出しを省くために、フォーム(cadr x)
はユーザ関数で呼び出される際に直接(car (cdr x))
に
展開されるように、このパッケージによってinline
と宣言される。
下記の宣言はすべて同等である。defsubst
フォームは関数を定義して
それをインラインにするのをすべて1度に行なう便利な方法だが、Emacs 19で
しか利用できないことに注意せよ。
(declaim (inline foo bar)) (eval-when (compile load eval) (proclaim '(inline foo bar))) (proclaim-inline foo bar) ; Lucid Emacs only (defsubst foo (...) ...) ; instead of defun; Emacs 19 only
注意せよ: この宣言は、含んでいるソースファイルが終わった後も 効果を残す。あなたが定義した関数がインラインになるべきと要求するために 使うことは正しいが、外部関数のインライン化を要求するために使うことは 無作法である。
Common Lispでは、ある関数への特別な呼び出しが単にその呼び出しを
インラインにする前に、(declare (inline …))
を使うことが
可能である; 現在のバイトコンパイラは、これを実装する方法を
提供していないので、(declare (inline …))
は現在はこの
パッケージによって無視される。
notinline
notinline
宣言は、結局インラインにすべきでない関数をリストする;
それは以前のinline
宣言を取り消す。
optimize
この宣言は、どのくらいの最適化がコンパイラによってなされるかを制御する。 当然、それは初期の非最適化コンパイラでは無視される。
語optimize
には、(speed 3)
や(safety 2)
のように
任意の数のリストが続く。Commons Lispは、いつくかの最適化“品質”を
定義する; このパッケージは、speed
とsafety
以外はすべて
無視する。品質の値は0から3までの整数であるべきである。
0は“重要でない”を、3は“とても重要である”を意味する。両者の品質の
既定レベルは1である。
このパッケージ中では、Emacs 19の最適化コンパイラの場合、speed
品質はbyte-compile-optimize
フラグに結びつけられ、
(speed 0)
の場合はnil
が、より高い設定の場合はt
が
設定される; また、safety
品質はbyte-compile-delete-errors
フラグに結びつけられ、(safety 3)
の場合はt
が、より
低いすべての設定の場合はnil
が設定される(後者のフラグは、その
副作用のみがエラーを通知する可能性があるようなコードを最適化し
去るかどうか(たとえばfoo
が実行時に束縛されるかどうかが未知の
場合に(progn foo bar)
をbar
に書き直す)を制御する)。
(safety 0)
でコンパイルしてさえ、Emacsのバイトコードシステムは、
真に害になることが起こらないようにするための十分なチェックを
提供することに注意せよ。たとえば、Emacs自身に重大なバグがなければ、
Emacsは単に完全に最適化されたLispプログラム中のエラーのために
セグメント違反でクラッシュすることはない。
optimize
宣言は、通常はファイルのトップレベルのproclaim
や
declaim
で使われる; Common Lispは、与えられたフォームに局所的な
最適化のレベルを設定するために、declare
と一緒に使われることを
許すが、これは最適化コンパイラの現在の版では正しく動作しないだろう
(declare
は新たな最適化レベルを設定するだろうが、そのレベルは、
囲むフォームが終わった後に自動的には設定解除されないだろう)。
warn
この宣言は、どんな種類の警告がバイトコンパイラによって生成されるかを
制御する。再度言うと、最適化コンパイラだけが警告を生成する。
語warn
には、最適化品質に似た形式の任意個数の“警告品質”が
続く。現在サポートされている警告の型は、redefine
や
callargs
、unresolved
、free-vars
である; 現在の
システムでは、0の値はそれらの警告を無効にし、それ以上のすべての値は
有効にする。詳細は最適化バイトコンパイラの文書を見よ。