# Duck typing and the Standard Library

**URL:** <https://www.ruby-forum.com/t/duck-typing-and-the-standard-library/74570>\
**Category:** Ruby\
**Created:** [November 7, 2006, 10:48am UTC](https://www.ruby-forum.com/t/duck-typing-and-the-standard-library/74570 "2006-11-07T10:48:33Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [November 7, 2006, 10:48am UTC](https://www.ruby-forum.com/t/duck-typing-and-the-standard-library/74570/1 "2006-11-07T10:48:33Z")

</div>

I’m new to Ruby, so please excuse any ignorance on my part. I read the  
following article about Ruby and “duck typing”:

[http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/100511](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/100511)

I got the impression that duck typing is the “right” way to do things  
in Ruby. However, the Ruby Standard Library itself doesn’t seem to use  
duck typing. Consider the following example:

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?

-Mike

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [November 7, 2006, 10:48am UTC](https://www.ruby-forum.com/t/duck-typing-and-the-standard-library/74570/2 "2006-11-07T10:48:36Z")

</div>

On 31.10.2006 10:19, removed\_email\_address@domain.invalid wrote:

> =\> true  
> (as the article says), then why does the Ruby Standard Library do it?  
> It is just giving you a nicer error message. Otherwise, this might  
> happen:

irb(main):003:0\> def foo(s) s=s.to\_set end  
=\> nil  
irb(main):004:0\> foo []  
=\> #\<Set: {}\>  
irb(main):005:0\> foo Set.new  
=\> #\<Set: {}\>  
irb(main):006:0\> foo 0  
NoMethodError: undefined method `to_set' for 0:Fixnum from (irb):3:in`foo’  
from (irb):6

Note that there must be an exception of some kind if the parameter is  
inappropriate. And no, this is not static typing.

Kind regards

```
robert
```

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [November 7, 2006, 10:48am UTC](https://www.ruby-forum.com/t/duck-typing-and-the-standard-library/74570/3 "2006-11-07T10:48:38Z")

</div>

removed\_email\_address@domain.invalid wrote:

> 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

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [November 7, 2006, 10:48am UTC](https://www.ruby-forum.com/t/duck-typing-and-the-standard-library/74570/4 "2006-11-07T10:48:39Z")

</div>

Robert K. wrote:

> > irb(main):001:0\> require ‘set’  
> > So, what gives? If it’s wrong to “try to make Ruby do Static Typing”  
> > irb(main):006:0\> foo 0  
> > NoMethodError: undefined method `to_set' for 0:Fixnum from (irb):3:in`foo’  
> > from (irb):6
> 
> Note that there must be an exception of some kind if the parameter is  
> inappropriate. And no, this is not static typing.
> 
> Kind regards
> 
> robert

Yes, there must be an exception of some kind if the parameter is  
inappropriate. The question is whether to explicitly check the type of  
the parameter and throw a nicer exception, or to explicitly _not_ check  
the type of the parameter and let the exception happen where it may  
(i.e. when a needed method does not exist).

Arguments can be made for both sides, but which is considered the “best  
practice” for Ruby development? The Ruby Standard Library suggests it  
is the former, but the article I referenced above suggests it is the  
latter.

-Mike

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [November 7, 2006, 10:48am UTC](https://www.ruby-forum.com/t/duck-typing-and-the-standard-library/74570/5 "2006-11-07T10:48:48Z")

</div>

Hi –

On Tue, 31 Oct 2006, removed\_email\_address@domain.invalid wrote:

> > > duck typing. Consider the following example:  
> > > above, which the article claims is not “the Ruby way”.  
> > > irb(main):005:0\> foo Set.new
> 
> is the former, but the article I referenced above suggests it is the  
> latter.

The way I’ve always looked at it is that the Ruby core and standard  
library do a certain number of things along these lines that are  
necessary for bootstrapping the basic classes into existence and  
dealing with their relations, but that aren’t necessarily what you’d  
do normally when using those classes. You get a lot more “type”  
errors (most of which are actually class errors) from the built-ins  
than from most other code.

The main disadvantages of testing for class/module ancestry are:

1. it doesn’t actually guarantee an object’s behavior;
2. it discourages thinking about more flexible ways of programming.

I think that in the case of some of the standard and core classes,  
these concerns don’t loom as large as they might in our programs. At  
the same time, there’s no particular reason for those classes _not_ to  
be more duck-type oriented, if that can be done without introducing  
any problems.

David
