「最低限の Squeak Smalltalk 入門」の補足…というか四方山話


最低限の…」にからめた、とりとめのない話。


>「コードを入力する場所くらいは用意しないといけない」

じつのところ、Squeak SmalltalkSmalltalk 式を評価するにあたっては、必ずしもワークスペースを用意する必要はありません(もちろん、ワークスペース変数を使いたい場合は別ですが…)。Squeak Smalltalk 環境では、文字が入力できる場所なら原則としてどこでも do it(alt + d)、print it(alt + p)で、入力・選択した式の評価ができます。

右クリック(第二ボタンクリック)メニューから「式を評価」(do it)や「式を表示」(print it)を選んでも同じ事ができますが、たまにメニューが使えない局面がある(イベントの奪い合いになったり、メニューの表示がブロックされている場合がある)ので、do it(alt + d)、print it(alt + p)のキーコンビネーションは覚えて使えるようにしておいたほうがよいと思います(それで、いちいち alt + ... としつこく書いています)。


>「ctrl の代わりに alt も使えます」

ctrl(コントロールキー)だといくつか使えないキーコンビネーションコマンドがあるので、個人的には alt のほうが好きです。というわけで、すでに上にもあるように、このエントリーでは alt + … と書いてしまっています。ctrl がお好みでしたら、適宜 ctrl に読み替えてください。Mac の場合は cmd(コマンドキー)です。


Smalltalk の影響を受けてつくられた Mac や、その強い影響下にあるシステムの GUI では、あくまでメニューコマンドが“本来”でキーコンビネーションコマンドはその“ショートカット”のための副次的なもの…という建前があるのですが、 Squeak Smalltalk ではやたらとキーコンビネーションコマンドが充実していて、メニュー操作の補助的な位置づけという色合いが薄められています。テキスト編集やコード評価のためのコマンドに重複はあるものの、他は互いに独自のものを含んでいます。

テキスト操作中などに使用できるキーコンビネーションコマンドの一覧は、デスクトップクリック → ヘルプ…(help...) → コマンドキーの機能を見る(command-key help) で得られます。キーコマンドでこんなことが!というもの(alt + shift + u による LF → CR 変換)や、なにに使うのかさっぱり…なもの(alt + y によるキャレット前後の文字の入れ替え)まで多岐にわたっていて面白いです。

他にも、Mac には受け継がれなかった again (alt + j。モードレスな検索・置換機能) が、個人的には大のお気に入りでよく使います。クリップボードを汚さずに入れ替えや複製ができる exchange (離れた二カ所を順次選択したあとに alt + e) や duplicate (複製先、複製テキストを順次指定したあとに alt + shift + d) も地味に役立ちます。コード入力支援機能では、Smalltalk-80 時代からある ifTrue: や ifFalse: の挿入(alt + shift + t もしくは f)に加え、query symbol (alt + q) の連打により補完されたキーワードセレクタに引数を挿入する際に使える advance argument (alt + shift + a で次のコロンの場所にキャレット移動) といったものが用意されています。

それぞれのキーコマンドがどういう機能なのか、あるいはそもそもどのようにしたら使えるのか(^_^;)…をより詳しく具体的に知るのには、ParagraphEditor>>#initialize から辿って対応するメソッドのコードを読むのがよいでしょう(上流メソッドの定義をたぐるには、クラスブラウザの「インプリメンタ」(implementors)ボタンが便利です)。ParagraphEditor のメソッド群はお世辞にもきれいなコードとはいえませんが、Squeak Smalltalk の特にテキスト入力周りの動きを知ったり、手を加えてその効果を楽しむ遊び場としては、適した題材ではないかと個人的には考えています。


一方で、各メニューコマンドでコールされるメソッドについては、メニュー項目を alt + shift + クリックで選択した状態で、シフトキーを押しながらデバッグハロー(右の列、上から二番目のグレイのボタン)をクリックして呼び出したインスペクタから、 selector あるいは arguments というインスタンス変数を探してその内容を見ることで(多くの場合)確認できます。


>「ワークスペースというのは、書き捨て用のメモソフト」

ワークスペースには、accept(alt + s。ビューとモデルの同期を意味する統一的な操作)をすると、警告無しで簡単にウインドウを閉じることができてしまうという不条理があります。これが「書き捨て」と称する理由です。改行 → 削除など適当な操作をして常にビューを変更状態(赤枠が表示される)にしておけば、クローズボタンを押しても「変更はまだ保存されていません。」(Changes have not been saved.)などと尋ねてくれるので内容が失われるのを回避できる、というバッドノウハウwがあります。

では、何のための accept(alt + s)かというと、本来ならば、モデルとビューを同期したあとにビューに加えられた変更をキャンセルして元に戻すのに使います。ロールバックのための操作は cancel(alt + l)です。ところが、ワークスペースには長らく修正されていないバグ(いったん accept(alt + s)すると、それ以降、モデルの内容がビューと常に同一になってしまう)があって、この cancel(alt + l)は実際には役に立たない…という悲しい現状があります(^_^;)。

ただ、一度でも accept(alt + s)しておきさえすれば、誤ってウインドウを閉じてしまっても(ガベコレ前であれば…)、Workspace allInstances collect: [:each | each contents] といった式を inspect it(alt + i)することで、内容を救うことが可能です。これもバッドノウハウ…かな(^_^;)。


なお、いちおう、ウインドウメニュー(ウインドウ左上、クローズボタンの右隣りのボタンをクリック)から「save contents to file...」を選ぶことでカレントディレクトリへファイル保存もできます。また、ワークスペースに限らず、右クリック(第二ボタンクリック)メニューが使えるところであれば、「さらに…」(more ...)→「内容をファイルに保存…」(save contents to file...)でも保存が可能です。失いたくない内容は(最初からワークスペースに書かない…という前提こそありますが)適当なタイミングで保存しておくのがよいでしょう。

頻繁に保存したい場合で、ワークスペース変数は別に使わなくてもいい場合は、(FileStream fileNamed: 'hoge.txt') edit などとして起動できる、ファイルリストというアプリのエディタモードを使うと、accept(alt + s)で保存できて、エディタ感覚でよいと思います。ただ、保存のたびに重ね書きの確認がポップアップしてくるので、少々うざったいですが…。


>「ワークスペース変数」

ワークスペース変数は、小文字で始まる変数をテンポラリ変数の宣言 | tempVar1 tempVar2 | をすることなく代入操作した場合に、ワークスペースオブジェクト(a Workspace)のインスタンス変数 binding に代入された辞書(連想配列)に逐次登録されます。

ある時点で、どんなワークスペース変数が登録されているのかは、ワークスペースオブジェクトのインスペクタを開くことによって比較的簡単に確認できます。現在編集中のワークスペースオブジェクトのインスペクタは、ActiveHand keyboardFocus editor model という式をそのワークスペース内で inspect it(alt + i)するか、あるいは、alt クリックでウインドウを選択 → デバッグハロー(右側上から二番目のグレイのボタン)をシフトクリック → 現れたインスペクタの左枠リストから model を探してダブルクリック で呼び出せます。ワークスペース変数のネタ元である Cincom SmalltalkVisualWorks)には、ワークスペース変数を一覧する UI が付いているので、そのうち Squeak Smalltalk にもつくかもしれません。

既存のワークスペース変数の破棄は、ウインドウメニューの reset variables で可能です。その下にある [■] automatically create variable declaration を選ぶと、ワークスペース変数の使用の可不可をトグルで切り替えられます(可不可の状態を示すインジケータは壊れているので気をつけてください → 次のバージョンの Squeak3.10 では直っているはずです)。ワークスペース変数の使用が禁じられた場合は、未定義の変数への代入や参照を行なおうとすると declare temp(テンポラリ変数として宣言するか?)か、タイプミスと見なしてインターンされた文字列から候補を探して列挙してくれます。


ワークスペース変数を使わずに、ワークスペース変数みたいなことをしたい(評価をまたいでオブジェクトを共有したい)場合は、グローバル変数を使います。 Smalltalk では大文字で始まるテンポラリ宣言をしていない変数は、グローバル変数と見なされ、コンパイル時にコンパイラが declare global(グローバル変数として定義するか?)と尋ねて来ます。ここで declare global を選べば、以後、この変数はシステム内のどこからでも参照可能になります。コンパイラの判断に頼らずとも、あらかじめ使いたい変数が決まっているときは、 Smalltalk at: #VarName put: nil とか、#(Var1 Var2 Var3) do: [:varName | Smalltalk at: varName put: nil] とかを do it(alt + d)することで、まとめて明示的に宣言しておくことも可能です。この方法なら小文字スタートの変数名も使えます。

イメージを保存しなければ保持されないので気にする必要はありませんが、もしきちんと消しておきたいと思ったならば、Smalltalk removeKey: #VarName とか #(Var1 Var2 Var3) do: [:varName | Smalltalk removeKey: varName] などとして消すことができます。

余談ですが、この「Smalltalk」という変数は、グローバル変数を保持する辞書(連想配列)です。自身もグローバル変数なので、自身に含まれます((Smalltalk at: #Smalltalk) == Smalltalk "=> true ")。昔は、これに nil を代入(Smalltalk := nil)した直後にイメージを保存するスクリプトを実行することで、システムを機能不全&起動不能に陥らせる無邪気な(違!)遊びがあったようです。ただ、現行の Squeak Smalltalk では、この「Smalltalk」へのカジュアルな代入はできなくなっています("=> Error: Cannot store into read-only bindings ")。


>「メソッドのバージョン管理機能を使わない今は入力内容は適当で大丈夫」

メソッドのバージョン管理機能は、クラスブラウザでメソッドを選択した状態で、中央のボタン群中程の「バージョン」(versions)ボタンをクリックして「バージョンブラウザ」を起動させることで利用できます。バージョンブラウザの上の枠にはそのメソッドの編集履歴が表示され、その最初の欄にしつこく入力を促されたイニシャル(シグネチャ)が使われる…というわけです。システムブラウザで適当にメソッドを編集して accept(alt + s)してから、改めてバージョンブラウザを開くと、履歴が増えているのが確認できるはずです。ちなみに、過去のバージョンに戻したい場合は、バージョンブラウザで戻したいバージョンをクリックして選択し、ウインドウ中央の「リバート」(revert)ボタンを押します。

バージョン間の比較は、整形後コードを比較する #prettyDiffs オプションを選んだほうが差がわかりやすいでしょう。


ちなみに「リバート」ボタンの右隣りにある「チェンジセットから削除」(remove from changes)は、「チェンジセット」という差分管理システムについて分かってくると重宝する機能ですので、今は無視してよいと思います。

右も左も分からない状態のとき、Smalltalk システムとストレスなくつきあうコツのひとつは、知らない and/or 今は知らなくても良いこと …には首をつっこまない“スルー力”を養うことと(逆をやって、調べ方も分からないうちに、目に付くものをかたっぱしから知ろうとすると確実にドツボります)、そうしてスルーしたものを完全には忘れてしまわず、あとで思い出すことができる“捨て目”を効かせておくことではないかな…と最近思うようになりました。w


>「アクセッサメソッドを自動生成」

クラスブラウザでは、対象となるクラスをブラウズ(選択)している状態で、クラス一覧(第二)枠の右クリック(第二ボタンクリック)メニュー → 「さらに…」(more...)→ 「アクセッサの作成」(create inst var accessors)で行えます。ちなみにこの「さらに…」で呼び出すことができる“裏”メニューは、「シフト黄ボタンメニュー(黄ボタンとは第二ボタンのこと)」とも呼ばれていて、その名の示すとおり、シフトキーを押しながら右クリック(第二ボタンクリック)することでダイレクトに呼び出すことができます。



まだまだ話は尽きないのですが、きりがないのでとりあえずこんなところで。