From: gabriele renzi Date: 2005-07-29T11:46:02+09:00 Subject: Re: method_missing crazyness Dave Fayram ha scritto: # Beware: just mumbling aloud, I understand that probably there is a # huge number of corner cases to consider wrt multimethods > On 7/28/05, Jeffrey Moss wrote: > >>Multimethods with optional typed argument lists would be totally awesome. It >>wouldn't break backward compatibility either. Wasn't that the most popular >>requested feature for ruby 2? > > > Aren't these against the spirit of duck typing, though? I thought that > Ruby was moving away from needing type-checking dispatch rather than > towards needing it. I don't really think duck typing and multiple dispatch are in the same pot. What I think (but notice I am usually dumb) is that the former is about doing something relying on property of a parameter (i.e. it responds to #meth and takes 4 arguments). The latter is just a better way, imho, to organize code and avoid things such as #coerce, the visitor pattern or things like: def find(*args) options = extract_options_from_args!(args) case args.first when :first find(:all, options.merge(options[:include] ? { } : { :limit => 1 })).first when :all options[:include] ? find_with_associations(options) : find_by_sql(construct_finder_sql(options)) else return args.first if args.first.kind_of?(Array) && args.first.empty? expects_array = args.first.kind_of?(Array) conditions = " AND #{sanitize_sql(options[:conditions])}" if options[:conditions] ids = args.flatten.compact.uniq case ids.size when 0 raise RecordNotFound, "Couldn't find #{name} without an ID#{conditions}" when 1 if result = find(:first, options.merge({ :conditions => "#{table_name}.#{primary_key} = #{sanitize(ids.first)}#{conditions}" })) return expects_array ? [ result ] : result else raise RecordNotFound, "Couldn't find #{name} with ID=#{ids.first}#{conditions}" end else # Find multiple ids ids_list = ids.map { |id| sanitize(id) }.join(',') result = find(:all, options.merge({ :conditions => "#{table_name}.#{primary_key} IN (#{ids_list})#{conditions}"})) if result.size == ids.size return result else raise RecordNotFound, "Couldn't find all #{name.pluralize} with IDs (#{ids_list})#{conditions}" end end end end Say, how do you add a :last option? you could subclass, or alias/redefine/call-redefined-method. If we had multiple dispatch (say, based on ===) you could just write def find(:last l) bla bla end I understand that there is some overlap with type cheking, but it is not the only thing. Probably, if you just add a rule such as "in absence of a specific method, call the first that was defined", you would get back duck typing just as it is now (i.e. it could fail or work) > The only time I've ever needed it is when I was doing some heavy math > code. When your set of types is small and well known, it is much more > elegant than loading up on the to_somethings or making a kind_of? if > statement clause. I often found I could have used it, but maybe I'm just short sighted. OTOH I wonder if we don't generally feel the need for this *because* we don't have it, I never realized how much useful an anonymous function could have been before I learned ruby.