¥chapter{デバッグ}

スクリプティング言語は、一般に「プログラミングしやすい」言語とみなされています。その理由のひとつは、ラピッドプロトタイプピングによる、よくテストしながらの開発スタイルにあると考えられる。しかし、どのようなソースコードにも必ずバグは存在し、モダンなプログラミング言語は、バグを発見するのを支援する機能を備えています。

Konohaは、いくつかの、例によって、本格的なデバッグ機能ではないが、クラスルーム利用においてデバッグの基本技法を学ぶのに十分なデバッグ機能をサポートしています。

== DEBUG ブロックとデバッグモード} 
¥index{DEBUG@DEBUGブロック}

デバッグは、バグの原因を分析するデバッグ情報をえることから始まる。そのためには、ソースコードを眺めているより、実際にプログラムを実行させて、内部状態の出力をえる方がバグを発見しやすい。

次は、簡単なバグの例です。プログラムが停止しなくなる理由を調べるため、引数 n|を表示しています。

{{{
int fibo(int n) {
	if(n < 0) print n;               // デバッグ情報の出力
	if(n == 0) return 0;
	return fibo(n-1) + fibo(n-2);
}
}}}

デバッグ情報は、特別な解析ツールを利用しない限り、プログラマ自身がプログラムして出力することになります。つまり、デバッグ情報の出力もソースコードの一部となります。こうなると、正規のソフトウェア機能とデバッグ情報の出力パートが混在し、いろいろ不都合が生じる。

Konoha では、DEBUG} ブロックと呼ぶ専用のステートメントブロックを導入し、デバッグのためのソースコードを分離して書くことができます。これは、後から述べるとおり、リリース/デバッグの実行モードを切り替えることで、デバッグ情報の出力を切り替えることが可能にします。

{{{
int fibo(int n) {
	DEBUG {                          // デバッグ情報の出力
		if(n < 0) print n;               
	}
	if(n == 0) return 0;
	return fibo(n-1) + fibo(n-2);
}
}}}

=== デバッグモードとリリースモード} 
¥index{でばっぐもーど@デバッグモード}
¥index{りりーすもーど@リリースモード}

Konoha は、デバッグモードとリリースモードの2種類の実行モードを持っています。デバッグモードは、開発者向けのモードであり、デバッグ情報を出力しながら実行する。リリースモードは、一般のユーザの利用を前提としたモードであり、逆にデバッグ情報を抑制して実行するモードです。

Konoha は、通常、リリースモードでスクリプトを実行する。デバッグモードで実行する場合は、起動オプションに -g| を用います。

{{{
$ konoha -g script.k
}}}

注意：対話モードは、-g|を付けなくてもデバッグモードとして起動される。¥¥

=== 実行時のモード切り換え} 

Konoha内部では、デバッグ/リリースモードの切り換えは、実行コンテクスト(Context})単位で行っています。そのため、Context}クラス関数を通して、実行中にモードを切り替えることもできます。

{{{
Context.setDebug(true);            // デバッグモードに変更
Context.setDebug(false);           // リリースモードに変更
}}}

「実行時のモード切り換え」を正しく使うためには、Konoha のスクリプト実行の内側まで注意する必要があります。スクリプトの実行は、厳密に言えば、コンパイル（コード生成）とコードの実行からなり、リリース/デバッグモードはコンパイル時のコード生成にも適用される。特に、リリースコンパイル時は、実行速度向上と利用メモリ量軽減を意図したコード最適化のため、DEBUG}ブロックと（後述する）print} 文、assert} 文は無視される。したがって、リリースコンパイルされたコードは、デバッグモードで実行してもデバッグ情報は表示されない。

=== @Release} アノテーション} 
¥index{release@Release}

クラス宣言やメソッド定義のとき、@Release| アノテーションを付けると、その対象となるクラスとメソッドは、デバッグコンパイルであっても常にリリース版のコードが生成される。十分に開発が完了した部分は、@Release| アノテーションを付けることで、開発チームにもコンパイラにも開発の進捗を明確に伝えることができます。

{{{
@Release 
class Person {
	...
}
}}}

注意: クラスに、@Release|アノテーションを付けると、そのクラスの全てのメソッドがリリースとなります。


== print} 文} ¥index{print@print文}

Konohaにおける正式なプリントアウト方法は、いわゆるOUT}定数を用いたOutputStream}クラスを用いた標準出力です。一方、古式ゆかしいprint} 文もサポートしています。これは、クラスルームにおいて、「print デバッグ」を教えるとき print文がないと都合がわるいからです。もちろん、誰にとっても「print} デバッグ」は有効であり、Konohaにおける print} 文は、「print デバッグ」専用の機能を備えています。

print 文は正式なプログラムの一部ではなく、デバッグ/リリースモードによって、プリントアウト出力のありなしが切り替わる。リリースコンパイルでは、そもそもprint}自体、無視される。

もうひとつの特徴は、print文は、デバッグ情報として加工された情報が出力されることです。まず、必ず print文が実行された位置が[ファイル名:行番号]として出力される。変数の値を出力するときは、（ご親切に）変数名も自動的に出力される。

{{{
>>> a = 0;
>>> print a;
[shell.c:4] a=0
}}}

単一のprint文において、複数の情報を出力する場合は、カンマで区切る。変数名以外の式を与えると、式の評価結果が表示される。

{{{
>>> a = 0; 
>>> b = 1;
>>> print a, b, (a+b);
[shell.c:4] a=0, b=1, 1
}}}

=== @Date} アノテーション*} 
¥index{@Date}

print文は、@Date| アノテーションを付けることができます。@Date|アノテーションは、print文出力に対し、デバッグ情報を出力した時刻を表示するオプションです。

{{{
>>> @Date print a, b, (a+b);
2009/12/24 00:00:00 [shell.c:4] a=0, b=1, 1
}}}

=== ロッギング**}
¥index{@Log}

Konoha プロジェクトでは、print文とロギング(syslog)との統合を検討し、@Log(ALART)|のようなわかりやすい拡張オプションを提供する予定です。

{{{
>>> @Log(PANIC) print name;
}}}

== assert文} ¥index{assert@assert文}

アサーション(assertion)は、表明と訳される。assert文は、プログラムが正しく動作するための前提条件を表明し、プログラムが表明された条件通り正しく動作しているか確認するデバッグ機能を提供する。

まず、正しいプログラムという概念を考えるため、簡単な例を考えてみたい。次のfibo()|関数は、引数n|においてn > 0|を満たす整数が与えられるという前提でプログラミングされています。しかし、利用者の方は原理的にfibo(-1)|とコールすることもできます。（その場合は、StackOverflow!!|がスローされる。）

{{{
>>> int fibo(int n) {
... 	if(n == 1 || n == 2) return 1;
... 	return fibo(n-1) + fibo(n-2);
... }
>>> fibo(-1)
** StackOverflow!!
}}}

ここで、「引数が負の数でも動作するようにfibo()|関数を作らなかった」方に責任があるのか、それとも「fibo(-1)|をコールした」方が悪いのか、という責任問題が発生する。どちらにバグの責任があるかはっきりしない場合は、デバッグすることができない。

今回は、もし前者の立場をとれば、あらゆる引数値の範囲を確認し、その範囲を超えた場合は、何らかの例外をスローする方法も考えられる。（ちなみに、勝手に引数の値を修正してプログラムを継続する修正はあまり望ましいデバッグではない。）

{{{
int fibo(int n) {
	if(n > 0) {
		if(n == 1 || n == 2) return 1;
		return fibo(n-1) + fibo(n-2);
	}
	throw new Arithmetic!!("Negative fibo");
}
}}}

逆に、負のフィボナッチ数列は通常、定義されていないため、そもそもfibo(-1)|がおかしいと考えてもよい。そのように考えても、プログラミング言語側はそこまで察することはできない。そこで、何らかの方法でfibo(n)|の正しい動作条件を表明しておく必要があります。

assert文は、プログラムの正しい動作を表明するステートメントです。assert文に続く、条件式には、正しい動作のときtrueになるように書く。

{{{
int fibo(int n) {
	assert(n > 0);
	if(n == 1 || n == 2) return 1;
	return fibo(n-1) + fibo(n-2);
}
}}}

assert} 文による表明は、実行時における動的な検査で判定される。もし表明に違反した場合は、Assertion!!|例外がスローされ、プログラムの実行は正常化されるまで実行が中断される。ただし、Assertion!!|例外の標準的な対応は、表明に違反したコードを探して、デバッグを行うことです。

{{{
>>> fibo(-1)
** Assertion!!: n > 0
}}}

注意すべき点は、assert文はデバッグ作業を助けるステートメントである点です。一般に、assert文は、頻繁にコールされる関数に用いると、パフォーマンス低下の原因となります。そのため、リリースコンパイルでは除去してコンパイルされる。リリース前に、徹底的にソフトウェアテストを行い、Assertion!!|例外が発生しないようにデバッグする必要があります。

=== リリース・アサーション} 

アサーションは、デバッグ用の機能です。しかし、リリース版であっても、致命的な実行結果をもたらす前に、アサーション機能によって処理を中断させたいと考える場合もあります。Konohaでは、@Release|アノテーションをassert文の前に追加することで、リリースコンパイル時でもassert 文がコード生成されるようになります。

{{{
@Release assert(n > 0);
}}}

注意：頻繁にアクセスされる箇所に、リリース・アサーションを用いると、性能低下の原因となります。リリース・アサーションの導入は慎重に検討すべきです。

=== assert} 拡張文法}

C/C++では、assert()|は関数(マクロ)で提供されています。Konohaでは、基本的に互換性を保った形で、ただし条件式に続けてステートメントを記述できるように拡張してあります。したがって、assert文の文法は次のとおりになります。

assert| ($expr$) $stmt$

ここでは、まず条件式$expr$を評価し、その結果がtrue}なら何もおこらない。もし、false}の場合、それに続くステートメント$stmt$が実行され、最後にAssertion!!|例外がスローされる。

何のための拡張文法かと言えば、要するにAssertion!!|が発生したとき、その瞬間のデバッグ情報を表示するためです。（ただし、意外と便利です。）

{{{
assert(n > MAX) {
	print n, MAX;
}
}}}

== utest文**}

Konohaプロジェクトでは、ユニットテストをサポートするための専用のステートメントを導入する計画です。

{{{
@Name("test name")
utest (n > 0) {      // テスト結果の表明
	// テストコード
}
}}}

== ブレークポイント**} 

Konohaの対話モードでは、デバッガ(gdb)の代表的なデバッグ機能をサポートする予定です。これらの機能は、バイトコードの実行時書き換えのAPIが整備したのち、拡張される予定です。


%¥chapter{実行性能に関する傾向と対策}
%スクリプティング言語は、C/C++に比べ、実行時の処理速度の遅さは、実行時の処理速度は遅いことになっていた。スクリプティング言語の目的が、プログラムの性能よりも実行処理速度になっていたためです。
%Konoha プロジェクトにおける最大の関心事のひとつは、スクリプティング言語エンジンの性能向上です。



