

Smalltalk ではスタックフレームも「コンテキスト」と呼ばれるオブジェクトです。ちなみに、実行中のコンテキストに容易にアクセスできるようにわざわざ thisContext という擬変数まで用意されています。Smalltalk には予約語は全部でたった６つしかない（他は self、super、nil、true、false）うちのひとつを使うわけですから、これはある意味、破格の扱いです。

こうした背景もあってか、はたまた私の単純な思い込みでか、Smalltalk のデバッガは「コンテキスト（や、その連なりによって表現されるコールスタック）をブラウズするためのツール」という性格が強いように感じられます。クラス用ブラウザがクラスブラウザ、インスタンス用がインスペクタなら、デバッガはコンテキスト向けに特別に用意された“第三のブラウザ”といったところでしょうか。







▼デバッガの起動 デバッガを起動するにはまずノーティファイアを呼び出します。ちなみに、Smalltalk ではデバッガを使うにあたって、モードの切り替えや特別なビルド操作のようなものは必要ありません（もっとも Edit-Build-Debug といった開発サイクル自体が Smalltalk にはないわけですが…）。 ノーティファイアは、割り込み操作（alt/cmd + ピリオド）や例外時、また、任意のオブジェクトへの「halt」メッセージの送信（通常は、ブレイクポイントを設置したい式のレシーバの直後に halt と挿入しておけばよいでしょう。モダンな Smalltalk 処理系と違い、Squeak Smalltalk ではブレイクポイントをハンドコードして指定する必要があります）により画面に現われるやや小さめのウインドウで、三つのボタンとコールスタックの一覧からなります。 デバッガは、このノーティファイア上段右端の Debug ボタン、もしくは、下に列挙されたコンテキストから任意のものをクリックすることで起動できます。

たとえばワークスペースなどで次式を do it（alt/cmd + d）してみてください。ノーティファイアが現われたら UndefinedObject>>DoIt をクリックします。 ( 1 halt to: 3 + 4 ) do: [ :each | each factorial] ちなみにノーティファイアにある他のボタンは、Proceed ボタンが処理の続行で、Abandon ボタンは処理の中断に使います（後者はノーティファイアをウインドウのクローズボタンをクリックして閉じるのと一緒）。

コンテキストのクリックと同時にノーティファイアが閉じ、入れ替わりにデバッガが起動します。 ノーティファイアやデバッガにおいて（いや。これらに限らずシステム内において…）コンテキストは原則として「レシーバのクラス名（実際にメソッドが属するクラス名）>>実行中のメソッド名」の形式で表記されます。ブロックでは、若干表記が変わります（[] in …）が、その扱われ方はほとんど変わりません。

また、ここでの例のように、組み込みのエディタなどで入力・選択した式やスクリプトを do it や print it でインタラクティブに評価した場合には、評価した式やスクリプトを本体に持つ #DoIt という名前のメソッドの実行として、通常のメソッド呼び出しと同様に扱われます。 これは、評価のための操作と同時に、その文脈での self のクラス（たいていは self は nil なのでそのクラスの UndefinedObject）に #DoIt という名前のメソッドとして定義され（そう。Smalltalk も Ruby 同様オープンクラスで、普段からこの機能を大いに活用しています）、self へのメッセージ「DoIt」の送信で呼び出されたあと、自動的に削除される …のだと解釈するとよいでしょう（実際にもそれに近いことをしています）。







▼ステップ実行 上のコンテキスト一覧からブラウズしたいコンテキストをクリックして選ぶと（あるいはデバッガ起動時にあらかじめノーティファイア上で選んでおくと）、そのコンテキストで実行中のメソッドのソースコードが中央の枠内に表示されます。 このとき、次に実行されるポイントが選択された状態になっていますが、単純にテキストが選択状態にあるだけなので、ちょっとしたマウスやキーボードの操作で簡単に解除されてしまいます。そんなときは、右端の Where ボタンで元の選択状態に戻すことが可能です。

ステップ実行操作のためのボタンとして、中央付近に並んだ Into、Over、Through の三種類があります。 Over ボタンは単純にワンステップの実行のみを行ないます。

Into ボタンは、次に新たに作られるコンテキストにブラウズ対象を切り替えます。

Through ボタンの動きは Over ボタンとよく似ていますが、do: [...] のようなブロック付きメソッドの呼び出しの際に、これを Over のときのようにワンステップにまとめてしまわずに、引数のブロック内の処理もステップ実行してくれます。

そのメソッドに潜りたいときは Into を使い、その必要がなければ Through で。ただしループをいちいち走査する必要がないときは Through の代わりに Over を…というように使い分けるとよいでしょう。 いずれのボタンも、メソッド中の最後の式まで実行を終えると同時に、ブラウズ対象を、呼び出し元のコンテキストに切り替えます。これまでブラウズしていたコンテキストは通常の実行時と同様、原則として破棄されるので、もうそこには戻れません。

Restart ボタンを押すと、ブラウズ中のコンテキストの実行ポイントをメソッドの最初の式に戻せます。 ただしこのとき、self や関連オブジェクト（self のインスタンス変数に代入されたオブジェクトたち）の状態はリセットされないので注意しないといけません。self の状態も戻さないといけない場合（self が状態を持つオブジェクトの場合たいていはそうですが…）は、次項のデバッガ備え付けのインスペクタで self の状態を編集するか、そのオブジェクトを生成しているもっとも前のコンテキストに戻ってそこからやり直す（そのコンテキストをブラウズした状態で Restart し、あらためて Into で目的のコンテキストまで戻ってくる）必要があります。 コールスタックの深いところにあるはずのコンテキストにアクセスしたいのに、なんらかの理由で表示されていないようなときは、Full Stack ボタンを押すと、それらをリストの下の方に追加できることがあります。

Proceed ボタンは（ノーティファイアのそれと同様に）デバッガを閉じて処理を続行します。





