A near flame-war has broken out on ruby-talk (www.ruby-talk.org). But, amidst the smoldering remains lie some of the most clarifying statements I’ve seen about Ruby’s class/type system.
I have to admit that this thread struck one of my most sensitive nerves in the Ruby programming world these days: people coming from statically typed languages trying to force-fit dynamically typed languages into behaving like their previous languages (e.g. Java, C++, C#). Specifically, new Ruby programmers are constantly looking for how to "document interfaces" in some strict, contractual way. That’s fine with Java and C#, where it really means something, but in Ruby it’s meaningless to check the class of an object on method invocations. What makes it worse is that they show up crusading to save the "loose typing" heathens from the damnation that only strict, static typing can prevent. I probably sparked the initial flame of the near-war, with a post containing:
As you can see, any code that that relies on this kind of "type checking" in Ruby is naive. Worse than that, the desire to shoe-horn Ruby into Java-like "strictness" can blind the user into missing the point, and therefore the full benefit, of what Ruby has to offer.
Rich Kilmer (richkilmer.blogs.com/ether/) had the following to say about this static-ish type checking:
The question is whether you write your methods to expect a certain "namespace" (Class/Module), or just simply a set of behaviors.
This is the first time I can remember someone referring to a class or module in Ruby as a "namespace" for collecting and grouping behaviors. That one sentence really cuts to the core of the matter. Great way to look at it.
Austin Ziegler (halostatue.ca) and David Black (rubygarden.org/ruby?DavidBlack) joined in with a deluge of great points, with David (who is quickly becoming the defacto authority on this issue), specifically focusing on the type != class issue:
(excuse this being a little out of context)
But I will want anonymous types, like: c = CGI.new c.extend(MyCGIModule) def c.another_method; ...; end The *class* of c is CGI, and the module/class *ancestry* of c is [MyCGIModule,CGI,Object,Kernel] (or something), but the *type* of c, Ruby being Ruby, is "the type which is the type of objects which have c's type". And that's just fine; there's no need for me to have a name for the type (since it's not encapsulated anywhere except in the interface of c anyway), as long as I design, test, and use c in a sensible manner. I only needed the name of a class to bootstrap the object, and the name of a module to modify it. Then type takes over.
So, to distill all this, Ruby has objects which have behaviors (in the form of methods). Methods are called via messages sent to objects. As a convenience, Ruby provides classes and modules as ways of grouping and categorizing semantically related behaviors.
I understood this topic before today, but as a result of this discussion, I feel like I understand it in a different and deeper way now.
If you’re interested in object oriented programming, whether you’re using a dynamically typed language or not, the thread is definitely worth a read.