Smalltalk のワークスペースは、(特に Squeak では)見た目はシンプルなただのメモ書きのためのウインドウに過ぎないのですが、Smalltalk 使いにはなくてはならない古くて身近なツールです。(次図は今から 40年ほど前の Smalltalk-76 の頃のワークスペース。当時は UserView というクラスに定義された workspace というメソッドの内容を表示するブラウザのコードペインを取り出してウインドウ化しただけのものでした。)
クラスやメソッドを定義したり閲覧・編集する「クラスブラウザ」、オブジェクトの状態を見たり変更したりする「インスペクタ」と共に、ちょっとしたコードの試し書きをするための専用のアプリケーションソフトのようなものだと考えることもできます。またケント・ベックが、このワークスペースでの日常的な作業を通じて xUnit の元祖である SUnit フレームワークを思いつくヒントを得たこともアジャイル界隈ではよく知られた話ですね;p[^1]。実は Smalltalk(の特に Squeak などのように、古きよき時代の Smalltalk-80 の性格を強く残している処理系)では、文字が入力できる場所ならばどこでもコードを書いて実行可能なので、この手のツールをあえて用意する必要はないのですが、ウインドウを開いてコードを書く(あるいはよく使うコードがすでに書いてある)というのはなんとなく便利だし安心感があります。いわゆるアフォーダンスというやつでしょうか。
ともあれ、このようなシンプルなワークスペースだったのですが、いつのころからか本家Smalltalk の VisualWorks ではどんどん機能が増えて賢くなってきました。ワークスペース変数もその一つで、たいへん便利なので Squeak にも同様の機能が取り入れられています。ワークスペース変数は、そのワークスペースでのみ使用できる変数で宣言なしに使用できます。
通常、Squeakでワークスペース以外の場所で、たとえば foo とタイプして print it (alt/cmd + p) すると、次のようにコンパイラにしかられます。
しかしワークスペースで同じことを試しても、「それは nil だ」と何のエラーも出さずに答えてきます。
このようにワークスペースには、評価・実行するコードに未宣言の変数が見つかると、これをワークスペース変数だと解釈して勝手に宣言して作ってくれる仕組みが存在します。なお、こうして自動で登録されたワークスペース変数は、ワークスペースのタイトルバー右寄りに設置されたウインドウメニュー(青い矢印のクリックでポップアップ)の inspect variables でインスペクト(個別の消去、変更、あえてここでやる必要もなさそうですが、必要なら追加)したり、reset variables で全消去も可能です。
さてこのワークスペース変数。コードの試し書きやオブジェクトの動作チェックにはとても便利な機能なのですが、ちょっと困った問題も引き起こします。そのひとつは、タイプミスなどで想定した変数名として記述できていなかった場合でも警告がいっさい出ないということです。これは変数宣言をほとんど排除してしまった Ruby などの言語でコードをべた書きしたときと同様に、思わぬトラブルの原因になります。ちなみに、同じくウインドウメニューにある automatically create variable declaration のチェックをオフにしておけば、他の場所と同じようにスペルミスについては警告を発してくれるようにはなりますが、同時に当然ながら使いたい変数はかならず宣言しなければならないうえ、評価をまたいで共有できないという従来の状態に戻ってしまうことも意味します。
既に定義済みのワークスペース変数は活用しつつ、スペルミスはちゃんと指摘して欲しいですよね。であれば、そう動作するようにシステムをさくっと書き換えてしまうまでです。 メタ機能を大事にする Squeak だからというわけではないのでしょうが、Squeak ではメニュー項目など通常は選択できないテキストであっても、一部は、shift キーを押しながらクリックすることで選択、編集できる機構(といってもコピーして持ち出す程度の用途ですが。でも、こういう文書を書くときに重宝します)があります。ワークスペースのウインドウメニューから件の automatically create variable declaration というメニュー項目も shift クリックして文字として選択できます。ちょっと表示は崩れますが、この状態のまま alt/cmd + shift + E (method strings with it) をタイプすると、選択したメニュー項目に関連するメソッド(たいていは当該メニュー項目等のウィジェットを生成しているメソッド)を手繰ることができます。
これをみると、mustDeclareVariables というインスタンス変数の真偽値が動作を決めているようなので、このインスタンス変数を参照するメソッド群は、ブラウザの中央部のボタン群にある vars ボタンを押してポップアップするメニューから mustDeclareVariables を選ぶと列挙できます。
たまたま最初に表示された bindingOf: がアタリのようです。mustDeclareVariables が真なら無条件に nil を返しているので、この判断をちょっと遅らせてやれば、すでにワークスペース変数として定義されているものがある場合は警告を出させずにすませられそうです。
ということでこんなふうに変更してみました。 これで automatically create variable declaration のチェックを入れた状態(デフォルト状態)で、一時変数としての宣言なしに当該変数(実際はワークスペース変数)に興味の対象となるオブジェクトを代入しておき、その後、automatically create variable declaration のチェックを外しておくようにすれば、定義済みのワークスペース変数(とそれに代入したオブジェクト)をそのまま活かしたままに、コンパイラのスペルチェックの恩恵もうけられるという状態にできます。ウインドウメニューからのモードの切り替えが頻繁で面倒くさい…ということであれば、automatically create variable declaration メニュー項目を alt/cmd と shift の同時押しクリックでモーフ(図形オブジェクト)としていったん選択した後、あらためて複製(緑)あるいはピックアップ(黒)のハロー(モーフ選択時にそれを取り囲むように表示される小さな○)をクリックしてデスクトップにでも設置しておけばよいでしょう。
余談ですが、コンパイラには大文字で始まる未定義の変数はグローバル変数かどうか訊いてきてくれる親切機能もあるので、たとえば Foo := #something を評価して警告で declare global を選び、いったんグローバル変数として利用できるようにしてしまえば、ワークスペースに限らずどこでも利用可能になるので、個人的にはワークスペース変数なんて使わずとも、これでいいような気もします。^^; 関連して、self haltOnce: 1 "HaltOnce := true". というコード片を self halt. の代わりにシステム動作などの解析時に挿入して使用するのが最近のマイブームです。