I'm currently reading "Holub on Patterns", an excellent volume on Object Oriented Programming Voodoo. The language of the book is Java and it makes extensive use of Java's Interfaces to avoid "The Fragile Base Class Problem".
This has me thinking a lot about proper Ruby coding techniques. What is Ruby's equivalent to a Java Interface?
module Interface
def some_method; end
def another_method; end
end
That doesn't really require you to provide those methods in a class that mixes them in. Perhaps:
module Interface
def some_method
raise NoMethodError, "Must be overriden!"
end
def another_method
raise NoMethodError, "Must be overriden!"
end
end
Of course, I guess the only point of something like this is type checking, which Java needs when it declares a variable, but Ruby does not. Given that, client code can easily check interface:
def my_method( interface )
interface.respond_to?(:some_method) or raise ArgumentError, "Invalid interface."
interface.respond_to?(:another_method) or raise ArgumentError, "Invalid interface."
# ...
end
But that probably doesn't gain you much over just trying to call the methods and throwing exceptions that way, I guess. Which brings us full circle to doing nothing at all.
Does Ruby combat The Fragile Base Class Problem with philosophy alone? I'm referring to Duck Typing here, of course. Let them pass in what they want and if it responds to all the right messages, we don't care what it is. In this scenario, we're not supposed to check "kind_of?" at all, right? In that case, how do you document a method like this?
class DatabaseTable
# ...
def export( exporter )
exporter.start_table
exporter.store_metadata(@name, @width, @column_names)
@rows.each { |row| exporter.store_row(row) }
exporter.end_table
end
end
You don't really just say, "Pass in an object that responds to X, Y, and Z." in the RDoc, do you?
The "exporter" argument should probably be a type, it seems to me. I guess in this case a module with empty methods is a fine choice. Then you can just override what you need. But wait, isn't that just a "Base Class"??? Might as well use a class then...
In case it isn't obvious, this message is mostly just me thinking out loud. However, I'm very interested in the opinions of others, which is why I'm thinking out loud on Ruby Talk.
I figure I'm probably just too much in Java mode right now (sorry, it's the day job) so that I can't see the Ruby answers. If you're reading my babble and thinking "You wouldn't do it like that in Ruby!", criticize away. You won't hurt my feelings.
James Edward Gray II
P.S. Book writers, are you listening?! I'm crying out for a Ruby OO Voodoo book!!!