Dave Fayram ha scritto:
# Beware: just mumbling aloud, I understand that probably there is a
# huge number of corner cases to consider wrt multimethods
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.