From: Mike Austin Date: 2006-03-21T19:03:50+09:00 Subject: Re: Method overload, care to improve? Points taken for the problems of the implementation, and the metameta solution is nicely done. However, I would like to see if it's possible to use the 'def' syntax for defining multimethods. Below is a version I have been toying with, keep in mind the 'self' problem still exists and it is very inefficient. Is it possible to execute a method in a specific context, or is there a way to make the following work correctly? class Generic def find_method( args ) methods(false).sort.reverse.each do |method_name| signature = method_name.split( "_" ).map do |i| eval i end result = args.zip( signature ).map do |m| m[1] == nil ? true : m[0].kind_of?( m[1] ) end return method_name if result.inject( true ) { |a, i| a and i } end raise NotImplementedError end end class MultimethodTest @@foo = Generic.new def @@foo.Fixnum( number ) puts 'foo( Fixnum )' end def @@foo.String_Numeric( string, number ) puts 'foo( String, Number )' end def foo( *args ) @@foo.send( @@foo.find_method( args ), *args ) end end t = MultimethodTest.new t.foo( 10 ) t.foo( "Hello", 10 ) Erik Veenstra wrote: > The "methods" are executed in the context of an Object object, > instead of in the context of a Test object... And it behaves > like a singleton... And it doesn't handle subclasses of a > Class.... > > No, I don't think it's a usable solution... > > The code below would probably work better. It uses the > monitor-function "def_overload" which uses Module#wrap_method > [1] to add functionality to an already existing method. If the > arguments of a call matches the fingerprint, the given block > will be executed, otherwise the previous definition of the same > method is checked/called. > > gegroet, > Erik V. - http://www.erikveen.dds.nl/ > > [1] http://www.erikveen.dds.nl/monitorfunctions/index.html > > ---------------------------------------------------------------- > > require "ev/metameta" > > class Module > def def_overload(method, *klasses, &block) > wrap_method(method) do |org_method, args| > nok = > args.zip(klasses).find do |a, k| > if k.kind_of?(Class) > not a.kind_of?(k) > else > not a.respond_to?(k) > end > end > > if nok > if org_method > org_method.call(*args) > else > raise NotImplementedError, "Method #{self}##{method} not > implemented for arguments #{args.inspect}." > end > else > block.call(*args) > end > end > end > end > > class Test > def_overload(:foo, Fixnum, :to_f) do |x, y| > x + y.to_f > end > > def_overload(:foo, Fixnum, Fixnum) do |x, y| > x * y > end > > def_overload(:foo, Fixnum, Float) do |x, y| > x / y > end > end > > t = Test.new > > p t.foo(10, 20) > p t.foo(10, 2.0) > p t.foo(10, "2") > p t.foo(10, :two) # Should fail... > > ---------------------------------------------------------------- >