J
James Edward Gray II
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!!!
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!!!