vieweditattachhistoryswikistopchangessearchhelp

Smalltalk/Squeak の“きまり文句”

Smalltalk/Squeak(Squeak システムで使うことができる Smalltalk 言語)を用いるとき、知っておくと便利、楽しいこと(コード片)を思い出したときに書き留めておくための場所。--sumim

目次



トランスクリプトウインドウの呼び出し


ActiveWorld findATranscript: ActiveEvent
"World findATranscript: nil でもやっていることは同じ"


解説

トランスクリプト(Transcript) は、Smalltalk システムにおいて(Mac OS を除いた)一般的な OS にある標準出力に相当するもの。Smalltalk での書き捨てのコードの結果出力は(コードを選択して)、出力が文字列でよいなら alt/cmd-p (print it)で、オブジェクトそのもので得たいときは alt/cmd-i (inspect it)で済んでしまうので標準出力的なものの出番は少なくなるが、それでも、まとまった文字列出力を得たいとき、しかし、ファイルに書き出すまでのものでもないときはトランスクリプトを使うのが便利である。トランスクリプトウインドウはデスクトップメニューの open... サブメニューから transcirpt を選択することで開くことができるが、このメニューコマンドはすでにトランスクリプトウインドウがあっても無視して新しいのを作って開く。トランスクリプトウインドウが複数あっても害はないが、どれも同じモデルを共有している(同じ出力をする)ので、ひとつあれば十分である。

トランスクリプトウインドウがすでにあればそれをアクティブに、なければ新しく作って開くショートカットは、デスクトップクリックで alt/cmd-t することで呼び出すことができる(デスクトップメニューがポップアップするが無視してよい)が、これをコードで行なうための“きまり文句”がこれ。ActiveWorld は World でも同じ。他方メッセージのパラメータは nil を含めてどんなオブジェクトでもよいが Active… で頭韻を踏んでいるっぽい部分や意味的にも美しいのでこれでよろしかろうと。もちろんパーソナルコンピューティングを標榜するユーザーを目指すなら、こういう用途を見越してさっさと PasteUpMorph >> #findATranscript などを定義してラップし、普段は World findATranscript の do it でシンプルに済ませるのがスジ、というのは言うまでもない。

なお、ActiveWorld、World、ActiveEvent は、クラスではなく、前二者は現在のデスクトップ(a PasteUpMroph。不定冠詞+クラスという表記は、そのクラスのインスタンス、場合によってはそのクラスのサブクラスのインスタンスを意味する。以下、同じ)、後者は UI フレームワークのイベント(a UserInputEvent)を束縛したグローバル変数。--sumim



トランスクリプトへの出力


Transcript cr; show: 'hoge'
"Transcript show: 'hoge'; cr; endEntry  とすれば、出力後改行となる"


解説

Transcript に show: anObject というメッセージを送信すると、送信時に添えられるパラメータ(任意のオブジェクト。式ならその評価結果)に asString を送信した結果(文字列)が、トランスクリプトウインドウ(があれば)に出力される。トランスクリプトウインドウが表示されていなければ、なにも起こらない。後からトランスクリプトウインドウを開いても過去の出力結果は残っていないので注意。出力に際し、トランスクリプトウインドウはひとつでも存在していればよく、かならずしもアクティブウインドウである(最前面にある)必要はない。

通常のスクリプト言語では出力のとき、最後に改行コードを添えるのが慣習とされるが Smalltalk では改行後に内容を出力するのが慣例となっているため、この“きまり文句”をよく見かける。cr を他に crtab、crtab: anInteger、space、space: anInteger、tab、tab: anInteger といった TranscriptStream のスーパークラスにあたる WriteStream の character writing プロトコルにあるメッセージに置き換えてもよい。なお、cr の直後にある ; を用いた書式は、カスケードと言われるレシーバを共有する複数の式をひとつにまとめるためのシンタックスシュガー。この場合 Transcript に cr 、show: 'hoge' という複数のメッセージを畳みかけるように送ることを意味する。Transcript cr. Transcript show: 'hoge' と2式に分けて書いても同じ。なお、式「Transcript cr」は評価結果としてたまたま Transcript を返すので Transcript cr show: 'hoge' と書いても同じ結果は得られるが、式の意味は通じにくくなるのでこういう書き方は嫌われる。

Transcript cr のみで改行もできるが、次回の Transcript への show: anObject メッセージ送信まで、トランスクリプトウインドウの内容には反映されない。トランスクリプトウインドウ表示内容の末尾に明示的に改行を入れておきたいときは、Transcript cr; endEntry とする必要がある。なお、Transcript は、クラスではなく、a TranscriptStream を束縛しているグローバル変数。--sumim



テキストファイルエディタを開く


(FileStream fileNamed: 'test.txt') edit


解説

fileNamed: aString のパラメータ文字列と同名で、FileDirectory default にあるファイルを(なければ作って)その内容をテキストエディタウインドウに表示する。このウインドウは、ディレクトリ表示やファイル一覧機能を欠いているが実体はファイルリスト(file list)でそのように扱える。alt/cmd-s (accept) で変更後のウインドウ内表示内容の保存が可能。

書き捨てのコードは通常、ワークスペース(workspace)を用いるのが常だが、最近のワークスペースにはワークスペース変数という便利だがやっかいなものが付いたため、せっかくの一時変数の宣言とそれに基づくスペルチェック機構も意味をなさない。タイプミスが多い人はこのテキストエディタのウインドウでコードを書いて評価するほうがなにかと不都合が少ないはず。

GUI では、デスクトップメニューの open... サブメニューから file... を選んだときポップアップするファイル名一覧メニューを使って同様のことができる。ただしこの場合、開くことができるのはすでに存在するファイルのみ。もちろん、パーソナルコンピューティングを標榜するユーザーを目指すなら…以下略。




コードの実行時間を計測する


[100 timesRepeat: [100 factorial]] timeToRun


解説

実行時間を計測したいコードを [ ] でくくってブロック(無名関数)にして、それに対して、timeToRun というメッセージを送信する。実行にかかった時間がミリ秒単位の整数で返値として得られる。Squeak/Smalltalk システムは、中間コードを介した言語処理系と言うよりは、仮想マシンベースの独立した OS のようなものなので、他の言語処理系と速度を競おうとする場合、Squeak/Smalltalk 環境内に自前に用意してあるこうした式の評価結果をもって対決することになる。

他の Smalltalk 処理系、具体的には VisualWorks との互換性を考えるなら、
Time millisecondsToRun: [100 timesReepat: [100 factorial]]
という決まり文句を覚えておいたほうが応用が利く。ちなみに、VisualWorks の仮想マシンはそのしくみの違いから Squeak のそれよりはるかに性能がよく、処理によっては 10 倍程度の実行時間短縮が期待できることもある。




バイトコードを見る


[3 + 4] method symbolic


解説

Smalltalk システムにおいて、Smalltalk 言語で書かれたプログラムは「バイトコード」と呼ばれる中間コードに変換され、実行時にはそれが逐次実行される。中間コードへの変換を「コンパイル」と呼ぶが、仮想マシンが「バイトコードインタプリタ」と呼ばれることからも分かるように、解釈のしかたによってはコンパイル型言語というよりは、インタプリタ形式に属する。“コンパイル”後の結果がどんなプログラムになっているのかを知りたいときに使うのが、この決まり文句。バイトコードを調べたいコードを [ ] でくくってブロックにし、それに method そしてその返値にあらためて symbolic というメッセージを送ればよい。この場合、ブロックの処理などもバイトコードプログラムに含まれているので、最初に現れる #jumpTo: から #blockReturn の手間までが、興味のあるコードのバイトコード版、ということになる。

すでにコンパイル済みのメソッド(a CompiledMethod)のバイトコードを知りたければ、ブロックにしたり、method メッセージを送信する必要はない。ただ、コンパイル済みメソッドを特定するメッセージ式の返値に対して、symbolic メッセージを送信すればよい。たとえば、
(Integer >> #factorial) symbolic
とやればレシーバ(整数、an Integer)の階乗を求めるための factorial という Integer クラスに定義された Smalltalk コードのバイトコードプログラムを文字列として得ることができる。やはり VisualWorks との互換性を意識するなら、#>> より、#compiledMethodAt: を覚えておいたほうがよいだろう。

バイトコードを眺めていると、バイトコードレベルでも 3 + 4 はちゃんと見かけはメッセージ送信になっているんだな…とか、逆に、#ifTrue:ifFalse はメッセージ送信ではなく、go to 文による処理に展開されているんだな…とかいろいろ分かっておもしろい。

Smalltalk システムを仮想マシンベースの OS のようなものだと見立てれば、バイトコードは、通常のプラットフォームでいうところのネイティブなマシン語に相当する。実際、やはりバイトコードインタプリタでも動作する LISP 専用のマシン「LISP マシン」の流れで、Smalltalk のバイトコードを直接実行できる Smalltalk マシンというのもあったそうだ。


このページを編集 (8451 bytes)


Congratulations! 以下の 1 ページから参照されています。

This page has been visited 5170 times.