vieweditattachhistoryswikistopchangessearchhelp

メッセージングで行なう「フリ」もしている Smalltalk

Smalltalk はすべてをメッセージングで行なっているように見せていて、それがある種のアイデンティティともなっています。たとえば、3 < 4 ならば(これは常に真だが…)「5」 を、そうでなければ(あり得ないが…)「6」を返す処理は、構文ではなく、

3 < 4 ifTrue: [5] ifFalse: [6]


という式として記述します。これは、3 < 4 の結果である true に対する「ifTrue: [5] ifFalse: [6]」というメッセージの送信式。もちろん、条件の 3 < 4 も 3 への「< 4」というメッセージの送信になっています。

ここで、[5] や [6] のような [ ] でリテラルを含む式をくくったものは、「ブロック」と呼ばれ、これも Smalltalk では処理を現わすオブジェクトのリテラル記述となっています。Smalltalk や Ruby のような言語が立脚するメッセージングパラダイムにおいては、メッセージの受け手であることがオブジェクトの満たすべき要件なので、このブロックもメッセージの受け手になれます(しかし、Ruby のブロックはオブジェクトではないので、Proc オブジェクトへ明示的、暗示的に変換する必要あり。為念)。

| block |
block := [3 < 4].
^block value    "=> true "


このことにもとづくと、先の「ifTrue: [5] ifFalse: [6]」は、[5] と [6] というブロックオブジェクトを引数に取り、#ifTrue:ifFalse: というメソッドをコールするメッセージ…と読み解くことができるのですが、ただ、内部的にはそのように解釈はしておらず、あくまでこれは、メッセージングというパラダイムに則っているフリをしているだけだという話です。


実際、くだんの式が内部的にどう解釈されているかは、コンパイル時に中間的に生成されているメソッド(これも Smalltalk ではオブジェクト…)に対して、symbolic というメッセージを送り、バイトコードを読みやすく表示させることで簡単に確認できます。

3 < 4 ifTrue: [5] ifFalse: [6].
^thisContext method symbolic

=> 37 <22> pushConstant: 3
   38 <23> pushConstant: 4
   39 <B2> send: <
   40 <99> jumpFalse: 43
   41 <21> pushConstant: 5
   42 <90> jumpTo: 44
   43 <20> pushConstant: 6
   44 <87> pop
   45 <89> pushThisContext: 
   46 <D5> send: method
   47 <D4> send: symbolic
   48 <7C> returnTop


なお、thisContext は実行中のメソッドのコンテキスト(Smalltalk ではこれもやはりオブジェクト…)を返す擬変数。

これを見ると分かるように、内部的にはただの条件分岐文に変換されてしまっていますね。3 < 4 や thisContext method symbolic といったメッセージ送信になっているならば、ここには send: ifTrue:ifFalse: といったバイトコードが含まれていなければならないのに…。

つまり、Smalltalk で条件分岐もメッセージ送信に見えるのは、あえてそう見せているだけ、というワケ。これは、Smalltalk のメッセージングにたいして感嘆するときも、はたまた批判を加えるときにも、予備知識として知っておいたほうがよいでしょう。


ちなみに、このことから分かるように、Smalltalk で「ifTrue: [5] ifFalse: [6]」のようなメッセージを記述しても、メソッド #ifTrue:ifFalse: がコールされることはありません。でも、次のように記述すれば当該メソッドをコールすることは可能です。

3 < 4 perform: #ifTrue:ifFalse: with: [5] with: [6]


--sumim

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


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

This page has been visited 1980 times.