ASPN ActiveState Programmer Network
ActiveState
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups


Recent Messages
List Archives
About the List
List Leaders
Subscription Options

View Subscriptions
Help

View by Topic
ActiveState
.NET Framework
Open Source
Perl
PHP
Python
Tcl
Web Services
XML & XSLT

View by Category
Database
General
SOAP
System Administration
Tools
User Interfaces
Web Programming
XML Programming


MyASPN >> Mail Archive >> ruby-talk
ruby-talk
Re: Duck typing and the Standard Library
by Vidar Hokstad other posts by this author
Oct 31 2006 2:20AM messages near this date
Duck typing and the Standard Library | Re: Duck typing and the Standard Library
mikeharder@[...].com wrote:
>  irb(main):001:0> require 'set'
>  => true
>  irb(main):002:0> s = Set.new
>  => #<Set: {}>
>  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
Thread:
mikeharder
Vidar Hokstad
Brian Hartin
dblack
Robert Klemme
mikeharder
dblack

Privacy Policy | Email Opt-out | Feedback | Syndication
© ActiveState Software Inc. All rights reserved