In message [ruby-list:8228] Re: Delegation
Yukihiro Matsumoto <matz / netlab.co.jp>


> |  1. このようにした場合,何か問題が起こり得るでしょうか.
>
> method_missingは「メソッドが定義されていない」時にしか呼ばれ
> ませんから,Objectで定義されているメソッドに対しては転送が行
> われません.delegate.rbでやってるのと同様の方法で明示的に転
> 送してやれば良いんでしょうけど.

  Object で定義されていて,Delegator で preserved でないメソッドを undef
  しているんで,結構大丈夫かな?

> |  2. 初期オブジェクトが不定な delegation を上手く書く,もっと上手いや
> |     り方は考えられるでしょうか.
 >
> method_missing以上の方法は無いと思いますよ.


  「とりあえず書いてみた」ものを回収できたのでちょっとこの後につけてみま
  す.

    1. 直接実行することができます.
    2. 引数で Future の例の方の,メインスレッドの待ち時間を変えることが
       できます

  あんまり使い道はなさそうですけど.Promise(lazy evaluation)はまだしも
  Future はシングルプロセッサだとあんまり面白くないですね.IO バウンドな
  スレッドがあると役に立つのかな?

  # 改ページは入らんはテキストを挿入すると勝手に空行をカットするは,どう
  # も Outlook Express は性に合わない (^^;
  # なんか変なものが出ていってたら教えてください.

===========================================================================
  柳川和久 @ 東大阪市 . 大阪府
  kjana / os.xaxon.ne.jp                                       June 8, 1998
「え,月ってただ空に描いてあるだけじゃなかったの? うそー」
「うそーってエレン....」

# これは delegator.rb からほぼそのまま持ってきたもの
class UDelegator
  def initialize(obj)
    preserved = ::Kernel.instance_methods
    for t in self.type.ancestors
      preserved |= t.instance_methods
      break if t == UDelegator
    end
    preserved -= ["__getobj__","to_s","nil?","to_a","hash","dup","==","=~"]
    for method in obj.methods
      next if preserved.include? method
      #eval "def self.#{method}(*args,&block); __getobj__.__send__(:#{method}, *args,&block); end"
      undef_method method               # これと method_missing だけが違う
    end
  end

  def method_missing(msg, *arg, &block)
    __getobj__.__send__(msg, *arg, &block)
  end

  def __getobj__
    raise NotImplementError, "need to define `__getobj__'"
  end
end

class Promise <UDelegator
  def initialize
    @proc = Proc.new
  end

  def __getobj__
    return @obj if @obj
    @obj = @proc.call
  end
end

def delay(&block)
  Promise.new(&block)
end

class Future <UDelegator
  def initialize(&block)
    @th = Thread.new(&block)
    @th.abort_on_exception
  end

  def __getobj__
    return @obj if @obj
    @obj = @th.value
  end
end

def future(&block)
  Future.new(&block)
end

if __FILE__ == $0
  class Foo
    def initialize(a); @a = a; end
    def [](i); @a[i]; end
    def []=(i, v); @a[i] = v; end
    def isa; type; end
  end

  puts "promise example"
  foo = delay {a = Foo.new([]); for i in 1..100; print "#{i} "; a[i] = i; end; puts; a}
  puts "here is `non touched' promise #{foo}"
  puts "# preserved method call: promise is not evaluated here."
  puts "foo.type = #{foo.type}"
  puts "# unpreserved method call: promise is `touched' here."
  puts "foo.isa = #{foo.isa}"
  puts "foo[10] = #{foo[10]}"

  puts

  puts "future example"
  st = 15
  st = ARGV.shift.to_i if ARGV.size > 0
  foo = future {sleep 10; a = Foo.new([]); for i in 1..100; print "#{i} "; a[i] = i; end; puts; a}
  puts "here is `non touched' future #{foo}"
  puts "# preserved method call: future is not evaluated here."
  puts "foo.type = #{foo.type}"
  puts "some time consuming task take place...."
  sleep st;
  puts "# unpreserved method call: future is `touched' here."
  puts "foo.isa = #{foo.isa}"
  puts "foo[10] = #{foo[10]}"
end