第04回
■
■SqueakではじめるSmalltalk入門 第4回
■
本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkがどんなものであるかを知っていただこう…というテーマで、最近話題のSqueakを紹介しています。今回は、簡単なSmalltalkコードを記述して実行してみます。
Smalltalk言語には文法というほどのものはありません。LispにおいてS式ですべてを記述できるのと同じように、Smalltalkではすべてをメッセージ式で記述します。メッセージ式とは、送りたいメッセージとそれを受けるオブジェクトを「object message」という順番でスペースで区切って記述するものです。Objective-Cでいうところの[ ]内に記述するアレです。
書式の“object”のところにはあらかじめオブジェクトを束縛しておいた変数、もしくは、新しくオブジェクトを生み出すリテラル式、あるいは、返値を期待する別のメッセージ式を記述します。“message”のところには、先のオブジェクト(レシーバ)に対して送信するメッセージを記述します。メッセージにはパラメータ(つまりレシーバとは別のオブジェクト)を伴わせるか否かで3種類あって、それぞれ単項メッセージ、二項メッセージ、キーワードメッセージと呼ばれます。
単項メッセージは、いわゆる引数をとらないメッセージです。なお、Squeakでは文字列リテラルはダブルクオートではなく、シングルクオートで括ります。一方、ダブルクオートはコメント文として解釈されます。
3 factorial "=> 6 "
Float pi "=> 3.141592653589793"
'Squeak' reverse "=> 'kaeuqS' "
キーワードメッセージは引数をひとつ以上とるメッセージで、引数の前にObjectvie-Cでお馴染みの「:」を置きます。ただ、Objective-Cとは違って、Smalltalk言語の場合、「:」の前には少なくとも1文字のアルファベットが必要なので「:」だけでメッセージの末尾に引数が追加されることはありません。
3 raisedTo: 4 "=> 81 "
'Squeak' copyFrom: 3 to: 4 "=> 'ue' "
Workspace openLabel: 'untitled' "ウインドウを表示"
二項メッセージは引数がひとつだけの特殊なキーワードメッセージと考えることができます。メッセージセレクタ(メッセージから引数とスペースを取り除いた文字列)はアルファベットを含まず、引数の前(つまりセレクタの末尾)には「:」は付きません。主に数式や等式などをメッセージ式として違和感なく表現するために用意されたものだと思われます。そう、Smalltalkでは数式(のように見える式)もメッセージ式です。たとえば「3 + 4」は、3と4の加算を意味する二項演算ではなく、「3に+ 4というメッセージを送信する」と解釈し、内部的にも(バイトコードへのコンパイルまでは)そう処理されます。
3 + 4 "=> 7 (和)"
3 * 4 "=> 12 (積)"
3 = 4 "=> false (等価か)"
3 ~= 4 "=> true (不等価か)"
3 // 4 "=> 0 (除算の商)"
3 \\ 4 "=> 3 (除算の余り)"
3 / 4 "=> (3/4) (分数オブジェクトの生成)"
3.0 / 4 "=> 0.75 (除算)"
メッセージが複数混在するとき、二項メッセージはキーワードメッセージに、単項メッセージは二項メッセージに優先して送信されます。たとえば「3raisedTo: 4 + 5 factorial」は「3 raisedTo: (4 + (5 factorial))」の順で評価されます。もちろん括弧で括ることで優先順位を明示的にしたり、評価の順番を変更することもできます。二項メッセージと単項メッセージのみが連続する場合は、左にあるものから順に送信され、その結果として返ってきたオブジェクト(返値)に対して次のメッセージが送られます。「3 + 4 - 5 3」は「((3 + 4) - 5) 3」、「Float pi sin」は「(Float pi) sin」です。なお、二項メッセージにおける加減算に対する乗除算の優先はありません。乗除を優先したい場合は、あらかじめ括弧で括っておく必要があります。
キーワードメッセージについては、これを連続して記述することはできません(別のメッセージセレクタとして解釈されてしまいます)。必ず括弧を使って最初のメッセージ式の返値に改めてメッセージを送ることを明示的にしてください。逆の例ですが「3 = 4 ifTrue: [5] ifFalse: [6]」は3 = 4の返値(当然false)にifTrue: [5] ifFalse: [6]というメッセージが送られることを意味し、「(3 = 4 ifTrue: [5]) ifFalse: [6]」のように解釈されることはありません。
では複数のメッセージ送信を織り込んだ、メッセージ式の例を見てみましょう。
(FileDirectory default fileNamed: 'test.txt') edit "ウインドウを表示"
この式は、まずFileDirectoryという(グローバル変数に束縛されている)オブジェクトに対してdefaultというメッセージを送って、仮想イメージがあるディレクトリを示すオブジェクトを得ます。それに対し改めて、fileNamed:'test.txt'というメッセージを送っています。ここで、test.txtという名前のファイルがあればそれを、なければ作ってそれを制御するためのオブジェクト(StandardFileStreamのインスタンス)が返ってきます。さらにそのオブジェクトに対してeditというメッセージを送ることで、当該ファイルを編集するファイルエディタ機能を持ったウインドウが現われます。括弧でメッセージ送信の順を変えて、editが'test.txt'という文字列オブジェクト(Stringのインスタンス)に送られることを阻止しています。
普段、ファイルを編集するだけなら、こんなメッセージ式の評価ではなく、別に用意されたFileListという名のファイラを起動してそのGUIを使います。ここでは、オブジェクトに対するメッセージ送信により各種オブジェクトの機能が発現していることを実感していただければ結構です。
実際にdo itして動作を確認してみてください。Workspace openLabel:'untitled'で開くのとは違ったウインドウが現われます。このテキストエディタ内でももちろんSmalltalkコードを入力して実行できます。Smalltalk環境内では文字入力を受け付ける場所ならどこででも、Smalltalkコードを入力して評価(必要なら結果を表示)することが可能です。次のコードを入力して選択(cmd+A)し、続けてdo it(cmd+D)すると、赤いペンでマウスの軌跡を描くことができます。
| pen |
pen _ Pen new.
pen defaultNib: 3.
pen color: Color red.
[Sensor shiftPressed] whileFalse: [
| position |
position _ Sensor peekPosition.
Sensor redButtonPressed
ifTrue: [pen goto: position]
ifFalse: [pen place: position]]
いささか稚拙ではありますが簡易ペイントソフトのできあがりです。shiftキーを押せば制御がGUIに戻ります。複数行のメッセージ式を区切るにはピリオドを使います。改行とタブ、余分なスペースはコードの見た目を整える以外の意味を持ちません。Smalltalkのコード中で使用する一時変数にはアルファベット小文字で始まる英数字を使用し、同じコード内であらかじめ「|」で括って宣言しておきます。変数へのオブジェクトの束縛は「_(アンダースコア。Squeakの画面では“←”と表示)」か「:=」で左辺に束縛したい変数を、右辺に束縛したいオブジェクトを返値に持つ式(メッセージ式かリテラル式)を置きます。
この短いコードとその動きから、どんなオブジェクトにどんなメッセージが送られているのか、じっくりと考えてみてください。なおこの記述は、ウインドウの黄ボタンメニューからaccept→overwrite that fileで保存できます。再び開くには、デスクトップメニュー→open...→file listで呼び出すことができるファイラ(FileList)を使うか、ひとつ前に示した「(FileDirectory…」という式を記述して評価します。ウインドウを閉じずに置いておき、環境を終了するときにsaveする、という方法でもよいでしょう。
次回はこのプログラムの解説と描いた絵を保存する機能の拡張を試みます。
このページを編集 (6643 bytes)
|
以下の 1 ページから参照されています。 |
This page has been visited 2181 times.