«前の日記(2003年05月05日) 最新 次の日記(2003年05月07日)» 編集

Matzにっき


2003年05月06日 [長年日記]

_ [日記] みつかった

こっそり書いてたんですが、いつの間にか見つかってしまいました。 別にいいけど。

あ、私は「blog」と「にっき」を区別しない人です。 あんなのたんなるスタイルの違いじゃないかと。

_ Matzさん

日本語で「Matzさん」と言われると恥ずかしい。 よければ「まつもとさん」でお願いします。> みなさま

_ [Ruby]ProcとBlock

callやyieldで私がなにを問題視しているのか理解できないとの指摘が多い(ような気がする)ので、 もう一度まとめてみたいと思います。分かってる人には繰り返しになりますが。

Rubyのブロックってのはもともとループの抽象化のために生まれたものですから、 以下のような性質を持ちます。

  • パラメータの受渡のセマンティクスは代入
  • nextでブロック評価の終了
  • breakでブロックが付加されたメソッドの終了
  • redoでブロックの評価の再スタート
  • retryでブロックが付加されたメソッドの再スタート

ブロックをオブジェクト化したProcオブジェクトも同じ性質を受け継いでいます。 ところが、普通の人が「手続きオブジェクト」に期待するのは、 無名の関数オブジェクトですから(私もそう期待します)、

  • パラメータの受渡のセマンティクスは引数渡し
  • returnでブロック評価の終了

の方が嬉しい場合が多いでしょう。後者は必須じゃないけど。

これはどういうことかっていうと、 誕生の歴史的には「オブジェクト化されたブロック」に過ぎなかったProcが、 その名前(ProcはProcedureの略だろう)と、他言語でからの類推により 無名関数として振る舞うことが期待され、期待とのズレが発生しているということなんでしょう。 lambdaなんて名前を用意している時点でこの期待は必然なんですが。

1.7ではこのズレをProcを実行する側(caller)が、 関数オブジェクト的に呼び出したい場合にはcall、 ブロック的に呼び出したい場合にはyieldで呼び出すことで対応しようと考えました。 ブロックの呼び出しにはyield文を使うわけですから、これはこれで自然かなと。

しかし、あるひとつのオブジェクトを関数的に呼んだり、ブロック的に呼んだりするもんでしょうか(いや、ない)。 とすると、ユーザにその選択を強制するのは不合理です。呼ばれ側(callee)がよしなに振る舞うべきでしょう。 コンピュータが決められることはコンピュータがやるべきです。

とうことで、新たにBlockクラスを導入して(BlockはProcのスーパークラス)、 ブロック引数で与えられるオブジェクトはBlock、 lambdaで与えられるオブジェクトはProcとするのはどうだろうか、と。 そうすると関数オブジェクトを期待する局面ではProcオブジェクトが得られ(Procの挙動は1.6までとほぼ互換)、 手続きオブジェクトを期待する局面ではBlockオブジェクトが得られてきれいにまとまるような気がしています。

問題は100%互換ではないことと、これを実現しようとするとeval.cをだいぶ修正しないといけないこと。

あと、パラメータ受渡のセマンティクスを見直すのも大変そう。でも、

lambda{|a| p a}.call(1,2)  # => [1,2]

がエラーにならないこと(これもズレが原因)に不満を持っている人は多いわけで、 「親切な言語」を目指すRubyとしてはなんとか救済してあげたいんですよね。

_ 模様替え

昨年秋に発生した「テレビがテレビ台に入らない」という異状事態をやっと解消する。 テレビを買うときには高さ・幅だけでなく奥行きも確認しましょう。

_ 昨日の疲れ

今日になって出るとは。ペダルボートを漕いだ足が痛いぞ。うう。


«前の日記(2003年05月05日) 最新 次の日記(2003年05月07日)» 編集