Nobuyoshi Nakada
10/5/2006 1:05:00 AM
Hi,
At Thu, 5 Oct 2006 08:18:24 +0900,
Gavin Kistner wrote in [ruby-talk:218056]:
> The Situation/Requirements
> --------------------------
> A class has 2 different methods.
> Each method needs a couple 'scratch' objects to perform its
> calculations.
> The methods call each other; they must not use the same scratch objects.
> It is expensive to instantiate a scratch object.
> It's not expensive to initialize an existing scratch object with data.
> We like OOP coding, and want to call these as methods of a receiver.
>
> Wasteful Example:
> class Foo
> def c1
> tmp1 = ExpensiveObject.new
> tmp2 = ExpensiveObject.new
> # stuff involving tmp1/tmp2
> result = tmp1 + tmp2 + c2
> end
> def c2
> tmp1 = ExpensiveObject.new
> tmp2 = ExpensiveObject.new
> # stuff involving tmp1/tmp2
> result = tmp1 + tmp2
> end
> end
Like this?
$ ruby eo.rb 5
#<Foo::ExpensiveObject: 1>
#<Foo::ExpensiveObject: 2>
#<Foo::ExpensiveObject: 3>
#<Foo::ExpensiveObject: 4>
#<Foo::ExpensiveObject: 5>
[:c1,
#<Foo::ExpensiveObject: 1>,
#<Foo::ExpensiveObject: 2>,
[:c2,
#<Foo::ExpensiveObject: 3>,
#<Foo::ExpensiveObject: 4>,
#<Foo::ExpensiveObject: 5>,
[:c1,
#<Foo::ExpensiveObject: 1>,
#<Foo::ExpensiveObject: 2>,
[:c2,
#<Foo::ExpensiveObject: 3>,
#<Foo::ExpensiveObject: 4>,
#<Foo::ExpensiveObject: 5>,
[:c1, #<Foo::ExpensiveObject: 1>, #<Foo::ExpensiveObject: 2>, []]]]]]
$ cat eo.rb
#!/usr/bin/ruby
module ScratchArgument
def scratch_method(name)
meth = instance_method(name)
define_method(name) do |*args0|
*eo = *yield
imeth = meth.bind(self)
(class << self; self; end).class_eval do
define_method(name) do |*args|
args.unshift(*eo)
imeth.call(*args)
end
end
args0.unshift(*eo)
imeth.call(*args0)
end
end
end
class Foo
extend ScratchArgument
class ExpensiveObject
@@count = 0
def initialize
@id = @@count += 1
p self
end
def inspect
"#<#{self.class.name}: #{@id}>"
end
end
def c1(tmp1, tmp2, i)
if i <= 0
[]
else
[:c1, tmp1, tmp2, c2(i - 1)]
end
end
scratch_method(:c1) do
[ExpensiveObject.new, ExpensiveObject.new]
end
def c2(tmp1, tmp2, tmp3, i)
if i <= 0
[]
else
[:c2, tmp1, tmp2, tmp3, c1(i - 1)]
end
end
scratch_method(:c2) do
[ExpensiveObject.new, ExpensiveObject.new, ExpensiveObject.new]
end
end
result = Foo.new.c1(ARGV.empty? ? 3 : ARGV.first.to_i)
require 'pp'
pp result
--
Nobu Nakada