Smalltalk 言語の記述は変態か?

否! いわせりゃ、単なる関数呼び出しにしか見えないものを Smalltalk ライクなメッセージ送信に読み替えさせる Ruby のほうがよっぽど変態です。w …とのっけからどーせ負ける喧嘩を売ったところでむなしいだけなので、ええ…認めます。たしかに Smalltalk コードの記述は変態です。変態ですけど、それなりのメリットもあるんです。


見慣れた ALGOL/SIMULA ライクな obj.method(arg1,arg2) 的記法との違いから、悲しいかな、脊髄反射的に敬遠される向きもあるようですが、Smalltalk の式の記述(および読解)に際しては、とてもシンプルな規則だけ知っていれば十分だったりします。Smalltalk にマクロのような機構がないことを考慮すれば、単純さや一貫性では LISP をも凌駕していると言ってもよいでしょう。その規則とは、

receiver message

たったこれだけ。わざわざ説明するのも申し訳ないような気がするのですが、念のため書くと、まずメッセージの受け手(receiver)を指定し、スペースで区切り、続いてメッセージ(message)を記述する…と、こんなかんじです。実際の式で例をあげれば、

'smalltalk' reverse     なら、'smalltalk' がレシーバ、reverse        がメッセージ
'smalltalk' indexOf: $k なら、'smalltalk' がレシーバ、indexOf: $k    がメッセージ
3 + 4                   なら、3           がレシーバ、+ 4            がメッセージ
#(1 2 3) at: 2 put: 100 なら、#(1 2 3)    がレシーバ、at: 2 put: 100 がメッセージ
Display border: (Rectangle fromUser) width: 2
                        なら、Display      がレシーバ、
                              border: (Rectangle fromUser) width: 2 がメッセージ
     (この場合さらに第1引数も Rectangle  がレシーバ、fromUser     がメッセージ)

…といったぐあいです。(引数を含めて「メッセージ」であることに注意してください!)

余談ですが、処理系としての Smalltalk はたいへんいいかげんなので、この形式さえ守っていればどんな記述も Smalltalk コードとして成り立ってしまいます。つまり、コンパイルがとおってしまうわけです。たとえば、

3 hoge

という意味不明の式も、3 がレシーバ、hoge がメッセージと解釈されるので、その意図(?)のまま、ちゃんとバイトコードに変換(コンパイル)されます。もちろん、実際に 3 に hoge というメッセージを送信するだんになって、そんなメッセージ(で起動可能なメソッド #hoge を)知らん、と 3 が主張してひともんちゃくあるわけですがそれはまた別の話。


「メッセージ式」と呼ばれる、このような Smalltalk における式の書き方は、あらためていうまでもなく、「オブジェクトへのメッセージ送信」というメタファ(というか、Smalltalk にとってその存在理由とも言うべき“ドグマ”←これ重要!)を文法に反映させたものです。が、このメタファに頭が慣れるまでは(あるいは Smalltalk を縛るドグマなんぞに興味のない向きはw)ALOGL/SIMULA/C++ ライクな関数呼び出しの記法やセマンティックスに置き換えて考えるのもよいかもしれません。

'smalltalk'.reverse()
'smalltalk'.indexOf($k)
#(1 2 3).at:put:(2, 100)
Display.border:width:(Rectangle.fromUser(), 2)

まあ、この要領で、3 + 4 も、

3.+(4)

と解釈できなくもないですが、あえてそうする必要もないでしょう。


注目していただきたいのは、at: 2 put: 100 → at:put:(2, 100)、および、border: (Rectangle fromUser) width: 2 → border:width:(Rectangle.fromUser(), 2) です。Smalltalk では、メッセージを記述する際に通常の言語の関数名にあたる#border:width:を、border:とwidth:というように「:」の直後で分断して、そこに引数(パラメータ)を順に挿入します。おそらくは、これが変態と称される原因のうち、最たるもののひとつだと言えそうです。なお、ここで「:」も関数名(メソッド名、Smalltalk ではセレクタとも言う)に含まれる点に注意してください。たとえば、メッセージ hoge とメッセージ hoge: 3 において、セレクタはそれぞれ #hoge と #hoge: なのですが「:」の有無により両者は別物として区別されます。

この変態記法のおかげで Smalltalk 的関数呼び出し(つまりメッセージ送信)には、ALGOL 系記法でありがちな複数の引数の順番で悩むことを少なくできる…というメリットがあります。もちろんそのような本来はドキュメント化したり、コメント記載とするのが常の情報を含めることで、関数名が冗長になりがち…というデメリット(というかトレードオフ)も生じうるわけですが、これについては Smalltalk システムが環境であるがゆえに提供が容易な、スペルチェッカや簡易補完機能などを使ってもらうことで、ユーザーの負担を最小限に抑える配慮がなされています。


このように、Smalltalk の式の書き方はたしかに見たかんじ、とても変態的です。しかし、その見た目ほど得体の知れないものではなく、上で示したように、たいへん簡単なルールで見慣れた書き方に変換可能な案外フツーなヤツなのです。どうぞ、臆することなく気軽に Smalltalk のコードに接して、その解釈にチャレンジしてみてください。