Selfish にメソッドオブジェクトを追加しました

Selfish のスロットの値割り当て方法を変更 - ¬¬日常日記

昨日は id:miura1729 さんのおかげで Selfish がぐっと Self っぽくなったので、これに刺激を受けてさらにメソッドオブジェクトをきちんと実装してみました。そんなわけでメソッドの書き方も変更になりました。しかもこの変更に伴なって、ついに、これまでの明示的な self を省略できるようになったのです!私はやれば出来る子でした!

  • 引数なし
    • Self: (| x = 1. y = 2. sum = ( x + y ) |) sum "=> 3"
    • Selfish: _(:x => 1, :y => 2, :sum => method { x + y }).sum #=> 3
  • 引数あり
    • Self: (| sumX:Y: = (|:x. :y| x + y) |) sumX: 1 Y:2 "=> 3"
    • Selfish: _(:sumXY => method(:x, :y) { x + y }).sumXY 1, 2 #=> 3

やっぱり暗示的 self がないと Self っぽくないですもんね、今回の変更で大部それっぽく見えるようになったんじゃないでしょうか。でも Kernel#method はひどいって言うか、もう Self を通り越して iolanguage のそれにしか見えません。うーん、残念ながらこれが限界です。

さて、最初に「きちんと実装」と書いたので、どうきちんとしているのかを解説しておきます。でも先日書いたのを読んでない方はまず先にこれを読んで下さい。

局所変数無き荒野を生きる - ¬¬日常日記

これに書いたように、Self には局所変数がありません。これを簡潔に実現するためには、暗黙の self をメソッドオブジェクト自体としてメソッドオブジェクトのコード部を評価してやれば良いわけです。もしメッセージの受け手となるデータオブジェクトを暗黙の self としてしまうと、メソッドの引数の扱いをどうするかという点で非常に悩ましくなります。ただし暗黙の self をメソッドオブジェクトとした場合、コード内で受け手となるデータオブジェクトにメッセージを送るのに不都合が生じないように、親スロット self* に受け手のデータオブジェクトを設定する必要があります。こうすれば、プロトタイプベースの利点を活かして、委譲によってメッセージを適切にデータオブジェクトに送信できちゃうわけです。素晴しい発想ですよね!

というわけなので、これを素直に実装しました。大体のところ、以下のような感じになっています。

module Selfish
  class MethodObject < Object

    def initialize(*keywords, &block)
      super({})
      @keywords = keywords
      @block = block
    end

    def call(reciever, *args)
      # set self
      @slots[:_self] = method { reciever }
      # set arguments
      0.upto(@keywords.size-1) do |idx|
        @slots[@keywords[idx]] = args[idx]
      end
      # eval
      instance_eval(&@block)
    end
  end
end

わー、とっても簡単ですね!もちろんこれにより、Self 同様に Selfish では局所変数はとても邪悪なものとなります。というのも、結局は Ruby のブロックを使っているので、局所変数の存在によってメソッドオブジェクトの評価において何らかの影響を受ける可能性があるからです。そういうわけですから、Selfish を使う場合はよろしく局所変数無き荒野をさまよって下さい。Ruby なのに「変数使うな」というのも無理なお願いだとは思いますが、とにかく使っちゃダメ!

Self に対する Selfish の利点としては、メソッドオブジェクトの中でメソッドオブジェクトを作成できること、またメソッドの再定義が可能なことです。再定義はプリミティブ扱いの Selfish::Object#add_slot を使わないといけないのでなんだか中途半端な感じなんですけどね。いずれこの辺はうまい事いくように考えておきたいと思います。

あとは Self world の移植と resend を実装すれば Selfish もいっちょまえになりそうです(全然関係ないけど、星里もちるの「わずかいっちょまえ」はいい話ですよね!)。これからも Selfish はちまちま手を入れていこうと思います。