Squeakをかじる その2

MacにSqueak4.3を入れました。前回入れたのは3.9だったかな。

前回から2年ちょい経っているのでまずはおさらい。壁紙をクリックしたり右クリックしたりするとメニューが出る。

起動直後

全部閉じる。クリックしたら出てくるメニューの上の方に「Browser」「Workspace」「Transcript」が並んでいるのでそれを全部起動する。適当に配置する。

前回、Workspaceのフォントが小さかったり等幅じゃなかったりして困った記憶があるけども、このバージョンでは右クリックで「set font」ってメニューがでるのでそれで設定することにする。知っているフォントを探しても見つからない。BitstreamVeraSansMonoって書いてあるのが名前からしサンセリフの等幅だと判断。

Workspaceにコードを書いて、選択してCmd+D(Do it)すれば実行される。何も選択してなければカーソルのある行を実行する?
値を見たいなら手軽なのはCmd+P(Print it)で実行され、結果がWorkspaceに書き込まれる。ここらへんのショートカットは全部右クリックメニューに書いてある。
もう一つの方法がTranscriptに書き込むもの。Transcript show: 'hello!'を実行するとTranscriptウィンドウに書き込まれる。改行がついていない。前回はTranscript show: 'hello!'; cr.などと実行して改行していた。

ここまでが前回のまとめ。前回は一応素数を計算するところまではできた。その後「よしじゃあクラスやメソッドを定義してみよう」と考えて、クラスの定義のための構文を探したりWorkspaceにそれを書いてみたりして期待通りに動かなくて心が折れた。今回はそこから。

Browserの使い方を習得しようとしなかったのが前回の失敗の元。
「出力するにはTranscript showを使います。改行はcrです」って言われて「はい、そうですか」という気持ちにはならない。「他に何があるの?っていうかJavaのSystem.out.printlnみたいに改行付きで出力するメソッドあるんじゃないの?それどうやって調べるの?」って思うよね。
そこでCmd+Shift+i(Explore it)、以下探索。Transcriptを探索するとa TranscriptStream ''と表示される。TranscriptStreamクラスのインスタンスということね。で、このTransriptStreamって書いてあるところを右クリックして出てきたメニューにbrowse full(b)と書いてあった。これを押してみるとBrowserでクラスの詳細が出る!(今気づいたけど、探索しないでいきなりCmd+bでも出る!なんで右クリックメニューに出てないんだ!)

でまたこのクラスブラウザの見方が最初わからなかった。クラスブラウザでクラスを作ることを避けていたのが原因だ。4つあるリストの左から1番目と3番目をクリックした時に下のスペースに表示されているものは「新しいクラス/メソッドを定義するためのテンプレート」だった。1番目はクラスのカテゴリ、3番目はメソッドのカテゴリらしい。何に使うのかはまだよくわからないけども、分類しておけるようだ。

そしてTranscriptStreamのメソッド一覧を眺めていると、showlnというメソッドが見つかる。めでたしめでたし。

ところでshowlnの定義を見ているとself nextPutAll: とか書いてある。これはどこで定義されているのか? TranscriptStream では定義されていない。選択してImplementersボタンを押したら出てくるかとおもいきや予想外に大量に出てくる。どうやってここで呼ばれる定義がどこにあるかを調べたらいいんだろう。まあこんなこと書いているけども、カンで WriteStream にあるだろうと思ってやっぱりそこにあったんだけども。それから後付で TranscriptStream の定義を見て WriteStream のサブクラスであることを確認したのだけども。

クラスブラウザを使って適当なクラスを作ってみよう。まず1番左のリストでadd itemしてMyCategoryって名前のカテゴリを作った。それをクリックすると下の欄にクラス定義のテンプレートが出てくる。これの「#NameOfSubclass」がクラスの名前、Objectの部分が親クラスになる。

Object subclass: #NameOfSubclass
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'MyCategory'

名前を#MyFirstClassに書き換えて保存すると2番目のリストにそのクラスが出て、3番目のリストに「no messages」と出る。あー、そうか、さっきこれをメソッドのカテゴリのリストって呼んだけど、Smalltalk的にはメッセージって呼んで欲しいのか。このリストをクリックすると、こんなテンプレートが出る。

messageSelectorAndArgumentNames
	"comment stating purpose of message"

	| temporary variable names |
	statements

さて、ようやくある程度分かったことで「RubyTraits-0.2 であそぶ - Smalltalkのtは小文字です」を試してみよう。

Trait named: #T

さっそくMessageNotUnderstoodとエラーになる。前回はここで心が折れた。でも今ならわかる。Traitをブラウズして、今回newはしていないのだからclassボタンを押してクラスメソッド(とSmalltalkでは呼ばないかもしれないが)を見るべき。あったあった。

named: aSymbol uses: aTraitCompositionOrCollection category: aString
	"Dispatch through ClassDescription for alternative implementations"
	^ClassDescription newTraitNamed: aSymbol uses: aTraitCompositionOrCollection category: aString

つまり使い方としてはこうだな。無事TってトレイトがMyCategoryの中に作られた。

Trait named: #T
	uses: {}
	category: #MyCategory

さて次はこれだ。ええと>>という名前のメソッドが…どこにもないな。

T >> hoge
    ^'T#hoge'

'Smalltalk by Example'を眺める。あった:

A typographic convention. Smalltalkers frequently use the notation “>>” to identify the class to which a method belongs, so, for example, the cellsPerSide method in class SBEGame would be referred to as SBEGame >>cellsPerSide. To indicate that this is not Smalltalk syntax, we will use the special symbol » instead, so this method will appear in the text as SBEGame»cellsPerSide

なるほど'>>'って表記はそうコードに書けという意味ではないのか。というわけでクラスブラウザでメソッドを定義する。将来的にはGUIを使わずに挙動のテストがしたいので、メソッドをコードで追加する方法がほしいな。MethodDictとかブラウズすればいいのか。Object methodDict at: #hoge put: #foo.でとりあえずmethodDictに突っ込むことはできたが、ここにブロックを入れてもメソッドとして呼んではもらえないようだ。

もう夜の1時なので続きはまた今度。