From: Vidar Hokstad Date: 2006-10-31T19:20:10+09:00 Subject: Re: Duck typing and the Standard Library mikeharder@gmail.com wrote: > irb(main):001:0> require 'set' > => true > irb(main):002:0> s = Set.new > => # > irb(main):003:0> s.superset? 0 > ArgumentError: value must be a set > > It seems like the "superset?" method explicitly checks that its > parameter is a set. This is approach #1 in the "duck typing" article > above, which the article claims is not "the Ruby way". > > So, what gives? If it's wrong to "try to make Ruby do Static Typing" > (as the article says), then why does the Ruby Standard Library do it? Good question. This is the offending method: def superset?(set) set.is_a?(Set) or raise ArgumentError, "value must be a set" return false if size < set.size set.all? { |o| include?(o) } end There's certainly no good reason to refuse to accept other classes that has #size and #all? I suspect one reason for this is that without it #superset? the way it's written will just quietly return the wrong result if you pass it a FixNum (like you did) That's one of the pitfalls of duck typing - sometimes things will look like they should work, and return results that sometimes may even look right, and things will just quietly fail. In this case, the issue is the FixNum#size returns the storage size of the number (4 on my platform), and so if you test it with Set's smaller than 4 items, it will just return false. A better way would be change the "set.is_a?(Set)" to "set.respond_to?(:all?)" (and optionally handle that case properly). So a possible replacement that handles both arrays (and anything else supporting #size and #all?) as well as anything that will work with Set#include? (such as FixNum) def superset?(set) if set.respond_to?(:all?) return false if size < set.size set.all? { |o| include?(o) } else return false if size < 2 include?(set) end end Vidar