ライブラリが使いやすくリッチだったら言語能力が貧弱でもなんとかなる


檜山正幸のキマイラ飼育記 - あなたの「極小なプログラミング言語」は? より。

プログラミング言語をうんと小さくするのは、ライブラリのほうにフォーカスしたいからなんです(僕の動機は)。ライブラリが使いやすくリッチだったら言語能力が貧弱でもなんとかなるような気がします。その「気がします」という感覚を確かめてみたいんです。


くしくも、ここ数日つづいている、“ちょ、それ、まさに、Smalltalk www!”シリーズ(?)の第三弾でツッコもうと思っていたら、すかさず(違う)別のエントリーで釘をさされてしまいました。

単に「できるだけ小さな言語仕様」ってことなら、いくらでも案はあると思います。「通常のプログラミング言語に類似の構文」という制限も別に意識しなくてもいいでしょう。


で、これをふまえて改めまして。


「通常のプログラミング言語に類似の構文」の“縛り”を解いてよいのであれば、やっぱり私は「メッセージング」というメンタルモデルと文法のみで構成される言語を推したいですね。でも、文法のほうは、メッセージングというメンタルモデルが構築できていない人向けの方便と考えることもできるので、必須ではないかも。まあ、世の中がすでに、メッセージングというメンタルモデルの存在をコンセンサスとしてよい状況であれば(反語的に)、Ruby のようにセマンティックスのみにとどめて、文法のほうは普通にしてもよいのかもしれません。


Smalltalk では、すべてはオブジェクトへのメッセージの送信という形で表現されます。必要なのはこれだけです(もちろん、一部の例外を除き… 参考:id:sumim:20060604:p1)。あと、手続きを表わすオブジェクト(たとえばブロックコンテキスト)とそのリテラル表現が必要であることも言い添えておいたほうがよいでしょうか。


条件分岐も繰り返しにも、特別な文法は必要ありません。すべてはオブジェクトへのメッセージ送信で済ませましょう。

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

ならば、3 への「< 4」というメッセージ送信。その返値である true に対しての「ifTrue: [5] ifFalse: [6]」というメッセージ送信。


実装としては、「< 4」というメッセージ送信に伴い、レシーバの 3 が属するクラス「SmallInteger」 に定義されたメソッド「#<」を起動。同様に、「ifTrue: [5] ifFalse: [6]」というメッセージ送信に伴い、true の属するクラス「True」に定義されたメソッド「#ifTrue:ifFalse:」の起動…というようになります。


ただし、実際の Smalltalk では、後者はバイトコードへのコンパイル時にインライン展開されてしまうので、True >> #ifTrue:ifFalse: は起動されません。

[true ifTrue: [#a] ifFalse: [#b]] method symbolic
  ...
  26 <71> pushConstant: true
  27 <99> jumpFalse: 30
  28 <23> pushConstant: #a
  29 <90> jumpTo: 31
  30 <22> pushConstant: #b
  31 <7D> blockReturn
  ...


余談ですが、True >> #ifTrue:ifFalse: というメソッド自体は実際に存在するので、そのソースにアクセスしたり、その定義を変更することは、他のメソッド同様に可能です(もちろん、変更したとしても、先のインライン展開された既存のコードの挙動には影響を及ぼせませんが…)。

(True >> #ifTrue:ifFalse:) getSourceFromFile asString
ifTrue: trueAlternativeBlock ifFalse: falseAlternativeBlock 
   "Answer with the value of trueAlternativeBlock. Execution does not 
   actually reach here because the expression is compiled in-line."

   ^trueAlternativeBlock value


どうしても起動したい場合は、メソッド「#perform:with:with:」や類似のメソッドを介すべく、次のように記述します。これでインライン展開はされません。

true perform: #ifTrue:ifFalse: with: [#a] with: [#b]
=> #a


一方、条件付き繰り返しは、a Boolean を返すブロックへのメッセージ送信として表現します。

[10 atRandom > 5] whileTrue


ブロックオブジェクトへの whileTrue というメッセージの送信に伴い、BlockContext >> #whileTrue というメソッドを起動する意味を持ちます。もっとも実際は、こちらもやはりコンパイル時にはインラインで展開されちゃうんですけどね…(^_^;)。

[[10 atRandom > 5] whileTrue] method symbolic
 ...
 30 <23> pushConstant: 10
 31 <D2> send: atRandom
 32 <24> pushConstant: 5
 33 <B3> send: >
 34 <99> jumpFalse: 37
 35 <A3 F9> jumpTo: 30
 37 <73> pushConstant: nil
 ...