Sean O'Dell wrote:
> That's just a confidence issue.  I don't care if the object coming in is 
> broken.  I'm not concerned about catching objects which are implemented 
> improperly; that's actually very rare.  If an object had a signature that 
> said "I am a hash-like object" that would be fine for me.  Duck typing and 
> checking respond_to? are completely inadequate, and it seems like people 
> argue those points because Ruby offers nothing else and so what are you going 
> to advocate?  It's those two or rolling your own interface identification 
> system, which I think is cheesy; that sort of functionality should come from 
> the framework.

Okay, I'm trying to sum up this thread as well as test whether my 
understanding of this whole typing issue in Ruby is more or less correct.

---

1. Ruby _has_ types. It's called classes. In fact, all OO languages 
which have a class concept (as opposed to some classless OO languages 
like Self, I think) implement types through classes. All object belong 
to a certain class. That class is the object's type.

2. However, Ruby does _not_ do type checking for you. This means, method 
declaration is not like this:

  def meth(a -> Hash, b -> Array); ...; end

Instead it's only like this:

  def meth(a, b); ...; end

And if you want to do type checking, you'll have to code it yourself:

  def meth(a, b)
    raise ArgumentError unless a.class == Hash
    raise ArgumentError unless b.class == Array
    ...
  end

3. Ruby also does not tag a variable with type. This means, you don't 
declare variable's type like this:

  var a -> Hash
  var b = Array

Instead, you just assign a value to a variable:

  a = {}
  b = []

and you can change a variable's value (and thus type) anytime you want 
by reassigning it.

#2 and #3 are perhaps what people miss when they move from C++/Java to 
Python/Ruby. I don't know whether Ruby will ever have #2 and #3.

4. Static type checking (or static typing?) is #2 and #3, done at 
compile time. This is what C++ and Java do. Ruby, of course, does not 
have type checking, much less static type checking.

5. "Duck typing" is basically no typing at all. Due to #2 and #3, we can 
just pass around any kind of value (object) to any method, and the 
method will just use that object as it wants. If the method needs to get 
something out of the object (i.e. "make it quack") then the method will 
just try to do 'obj.quack'. If the object fails to quack, then it's not 
the right kind of object.

6. Object#respond_to? is not really related to typing (as in #2 and #3). 
Its primary usage is to avoid 'obj.quack' to raise NoMethodError, i.e. 
by checking first whether obj has a quack method.

7. Aside from classes as types, some OO languages (like Java and Perl 6) 
also have interfaces/protocols as another sort of type checking. Ruby 
does not have it, and I don't know whether it ever will. The choice is 
currently to implement your own interface mechanism. Probably by 
creating an Interface class and its subclasses (and thus creating the 
interface hierarchy) and then tagging objects with these interfaces, 
e.g. adding an 'implements' method to an object which will return a list 
of interface classes that object implements.

---

So to do type checking, either:

a) use classes, and use Object#kind_of? and Object#class for type 
checking (as in #2).

b) implement an interface mechanism (as in #7).

Sean seems to choose b), but reading the other posts, he also seems to 
be able to control the generation of the incoming objects. Then why not 
consider a) too? Instead of saying "hey, anything but a hash-like object 
here is an error" then why not require every incoming object to be a 
subclass of Hash and say, "raise ArgumentError unless obj.kind_of? 
Hash". Ruby allows an object (like an empty hash) to be extended with 
methods, so you can easily wrap object inside a hash and still be able 
to do type checking with the simple kind_of?(Hash).

-- 
dave