On Tue, Sep 24, 2002 at 01:38:02AM +0900, Brian Denny wrote:
> if "length" were part of the Enumerable interface, i would consider the
> above behavior to be a defect in the library.  but it's not.  the point is
> that i, as the user of a library, can expect to be able to make certain
> assumptions when i know that an object is of a certain type, as defined by a
> class or an interface/module, that i cannot make if i just know that they
> both respond_to? the same symbols.

Enumerable is a mixin, not an interface.  It's used to add additional
methods to a class that already has an each() method.  Because a class
includes Enumerable doesn't mean that an instance of that class will
have all the methods defined in Enumerable (I can remove or undefine
them), nor does it mean that a class that doesn't include Enumerable
lacks an each_with_index() method that has the same semantics as the one
in Enumerable.  In Ruby, an object's class just isn't a very good
measure of an object's type.

As you pointed out, the set of method names an object responds to is
also not a good measure of the object's type, because it's possible to
have to objects that both respond to the same method, but to give the
method different semantics for each object.  This is why using
respond_to? to check an object's "type" is frowned upon.

I know of no good way to check for the semantics of an object's methods
except by calling those methods; this is where unit tests come in.

An alternative is to use modules as if they were interfaces, but I have
not yet seen an implementation that does this well.  I'm also not sure
it would be widely accepted in the Ruby community.

In the case of String#length and String#each, the problem is that each
iterates over the lines in the String, while length tells you how many
characters are in the String.  IMO, this is a bug in String's interface;
as a result, I rarely call String#each directly, but instead call
String#each_byte or String#each_line.

Paul