表明 (プログラミング)表明(ひょうめい、英: assertion)とは、プログラミングにおける概念のひとつであり、そのプログラムの前提条件を示すのに使われる。アサーションとも呼ばれる。表明は、プログラムのその箇所で必ず真であるべき式の形式をとる。多くの言語ではそのような前提条件のチェックに表明を使用するが、設計上の判断を文書化するのに使う場合もある。表明が偽となった場合、プログラムにバグが潜在していることを示している。これを「表明違反; assertion failure」と呼ぶ。表明を言語構文や標準ライブラリとしてサポートするプログラミング言語も存在する。 プログラマは、開発過程でソースコードに表明を追加する。デバッグを単純化し、問題を早期に検出するためである。表明違反はバグを示していることが多いため、表明の実装では問題の元を示すために追加情報を表示するようになっていることが多い(ソースコードのファイル名と行番号、スタックトレースなど)。ほとんどの実装では、そのプログラムの実行が即座に停止する。 例例えば、次の疑似コードには2つの表明が含まれている。 x := 5
{x > 0}
x := x + 1
{x > 1}
この例では、アントニー・ホーアが1969年の論文で採用した表明の記法を使っている[1]。この記法は主なプログラミング言語では採用されていない。しかし、実行時にチェックされない表明としてコメントにこの記法で書いておくことはできる。例えばC/C++では次のようになる。 x = 5;
x = x + 1;
/* {x > 1} */
コメント内の表明を括弧で囲んでおくことで、他の通常のコメントと区別しやすくなる。 使用法Eiffelのような言語では、表明は設計工程の一部である。CやJavaでは実行時に前提条件をチェックするだけである。いずれの場合も実行時に正当性をチェックすることができるが、ソフトウェアの開発時(デバッグ時)のみ有効化され、最終的には(ソフトウェアのリリース時には)無効化(抑止)されることが多い。 契約による設計としての表明表明を仕様書の一種と見ることもできる。コードの部分が動作する前に期待される状態(事前条件)を記述し、そのコードを実行した後に期待される状態(事後条件)を記述する。また、クラスの不変条件を記述することもできる。Eiffelではそのような表明は言語に組み込まれており、そのクラスの仕様書の自動生成に使用される。これは契約プログラミングの重要な部分でもある。 この手法は、契約プログラミングを明確にはサポートしていない言語でも利用価値がある。コメントではなく表明を使用する利点は、表明がプログラムの実行毎にチェックされる点である。表明が真でなくなると、エラーが表示される。これによりコードの実装が表明とずれてしまった場合を早期に検出する。これはつまり、コメントとコードの内容の不一致の問題と同じである。 実行時チェックとしての表明表明はプログラマが前提条件としていたことがプログラム実装中にも保持され、プログラム実行時でも正しいことを保証するのに使われる。例えば、以下のJavaコードを見てみよう: int total = countNumberOfUsers();
assert(total >= 0); // total must be non-negative
if (total % 2 == 0) {
// total is even
} else {
// total must be odd and non-negative
assert(total % 2 == 1);
}
Javaでは この技法の主な利点は、問題が発生したときにそれを即時かつ直接的に検出できる点であり、後から検出しても様々な副作用によって真の原因がなかなかつかめないことがある。表明違反はコード上の位置を表示することが多いので、煩雑なデバッグ作業なしで問題点を即座に発見することができる。 表明は決して実行されないと見なされている箇所に置かれることもある。例えば、C、C++、Javaのような言語で、 Javaでは、表明は Cでは標準ヘッダファイル 表明はメモリの内容を書き換えてしまったり、スレッドの動作タイミングを変えてしまったり、といった副作用を持つ危険性がある。表明はプログラム本体への副作用を生じないよう注意深く実装する必要がある。 開発サイクル内での表明開発中、プログラマは表明を入れた状態でプログラムを実行する。表明違反が発生すると、プログラマに即座に問題が通知される。ほとんどの表明の実装ではプログラムの実行も停止する。プログラムがそのまま実行を続けてしまうと問題の原因を究明することが困難となる可能性が高い。表明違反で表示される情報(違反発生箇所やスタックトレース)を使えば、プログラマは容易に問題を解決できる。このようにして表明はデバッグ工程を単純化する。 静的表明コンパイル時にチェックされる表明は静的表明と呼ばれる。静的表明は言語規格で規定されていない数値型のサイズをコンパイル時にチェックするといった用途のほか、コンパイル時のテンプレートメタプログラミングに特に有効である。D言語は静的表明 旧規格のC/C++でも、表明違反となったときのみ不正なコード(コンパイルエラーとなるコード)が導入されるようにすることで、静的表明を実装可能である。例えば、C言語では次のように静的表明を実装できる。 #define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;}
COMPILE_TIME_ASSERT( BOOLEAN CONDITION );
もう1つのC言語でよく知られている静的表明の実装として、次の方式がある[6]。 static char const static_assertion[ (BOOLEAN CONDITION)
? 1 : -1
] = {'!'};
これを何度も使用するには、配列名がそれぞれ別々でなければならない。最近[いつ?]のメジャーなコンパイラにはプリプロセッサに Boost C++ライブラリではC++03以前でも利用可能なマクロ 表明の抑止表明は有効化/無効化を切り替えられるよう多くの言語で実装されている。表明は本来、開発ツールであるため、最終テストおよびリリース時には無効化する。したがって有効化時/無効化時の違いがプログラムの意味的な違いを生じないことが前提にある。換言すれば、表明は副作用を持っていてはならない。 CやC++を含む多くの言語では、表明は、リリースコンパイル時にプリプロセッサによって完全に除去される。Javaでは、表明を有効化する場合、実行時にオプションの指定を必要とする。オプションの指定がない場合、表明は無視される。 エラー処理との比較表明とエラー処理ルーチンを区別することには意味がある。表明は論理的にありえない状況をチェックするのに使うべきである。もし、「ありえない」ことが起きたとしたら、根本的に何かが間違っていたということである。エラー処理は通常発生しうるエラーを処理する(もちろん、一部の状況はほとんど「ありえない」かもしれない)。表明をあらゆるエラー処理に使用するのは賢明ではない。表明ではエラーからの復旧が考慮されておらず、表明違反は無条件でプログラムを停止させてしまう場合がほとんどである。表明はユーザー向けのエラーメッセージも表示しない。 エラー処理に表明を使っているC言語の例を以下に示す。 int *ptr = malloc(sizeof(int) * 10);
assert(ptr != NULL);
/* ptr を使用する。 */
ここで、プログラマは 表明の引数である式の副作用に依存するという間違いをすることもある。表明は条件の評価(バグがないことの確認)に使われるものであって、全く実行されないこともあることを常に念頭に置いておく必要がある。最終的にプログラムに問題がないと判断すれば表明を抑止する可能性がある。 例えば、次のようなC言語のプログラムがあるとする。 int *ptr;
assert(ptr = malloc(sizeof(int) * 10)); /* malloc() が失敗すると NULL を返す。しかし、この文は NDEBUG シンボルを定義してコンパイルすると実行されなくなる。 */
/* NDEBUG を定義してコンパイルすると、この時点で ptr は設定されていないことになる(未初期化)。 */
/* ptr を使用する。 */
...
一見すると、 歴史プログラムの正しさを証明する手段として表明の概念を最初に提案したのはアラン・チューリングである。1949年6月24日、ケンブリッジ大学で行った "Checking a Large Routine" と題した講演で「大きなルーチンが正しく動作していると確認するにはどうしたらよいだろうか? 確認する人物に多大な負担をかけないようにするには、プログラムの全体としての正しさを容易に確認できるようプログラマが個別に確認可能な明確な「表明」(assertions) をいくつもするべきである」と述べている[11][12]。 脚注
関連項目外部リンク
|
Portal di Ensiklopedia Dunia