On Saturday, July 17, 2010 08:21:10 pm James O'Brien wrote:
> I have found the concept of an interface invaluable in my Java programming
> and wondered if there were an equivalent concept in Ruby?

Yes and no.

Yes, there is certainly a concept of an "interface" -- this is an abstract 
concept that really applies to all languages. But no, it's not built-in to the 
language.

More specifically, the Java concept of an interface is only really needed 
because Java is statically typed.

> as a thought-experiment I
> propose Java without interfaces would be worse

Probably.

Take some common examples from the Java standard library -- Map would be a 
good one. Now, Interfaces are especially cool because I don't have to care 
that an object actually uses a hash internally -- it might use btrees, it 
might use something entirely different -- all I care about is that it claims 
to behave roughly like a Map is supposed to, and it presents get(), put(), and 
so on.

So, for example, I could declare an object to have a type like this:

Map<String, List<String>> files;

You could conceivably store these files as a HashMap, mapping filenames to 
lists of lines in the file. Of course, the cool part about interfaces is that 
it could also be a thin wrapper around a real filesystem (so you don't have to 
slurp them all at once), or it could talk to a database, or any number of 
things.

But on closer examination, was that actually the right abstraction? What are 
you doing with those files that you care that they're lists of strings, and 
not one giant string or an IO stream of some sort?

In the statically-typed world of Java, it makes sense that you would define 
your interfaces up front like this, because everything needs to have a type, 
and types are all defined and planned out ahead of time. It's not just that 
it'd be horrible design to do this:

Object files;

It's that it wouldn't work -- in order to call any methods on it, you still 
need to typecast it to something you know how to interact with.

In Ruby, things are a bit different. We have this concept called "duck typing" 
-- if it quacks like a duck, it may as well be a duck, who cares what it 
actually is? If it isn't a duck, it should break our unit tests, which is I 
think where it ties in to your comments here:

> I'm well versed in
> the benefits of test driven code and documentation but we have this in Java
> too

Since Ruby is dynamically-typed (and duck-typed), I don't specify the 
interface I need -- at least, not directly. I specify it by how I actually use 
the object in question:

puts files['readme.txt']

Now, there's still an implicit interface -- in this case, "Something that 
responds to [], and returns something which puts knows how to turn into a 
string." But I don't have to spell that out in code -- again, either it works 
(which it does, 99% of the time) or it causes a runtime issue, which is what 
unit tests are for.

That's the crucial difference -- in Ruby, I can just blindly fire a method 
call on an object, without knowing what type it is. In Java, I can only call 
methods on the object when I know it's of a type that supports those methods, 
and which type it is.

So, in Java, interfaces actually let you do things you wouldn't otherwise be 
able to do. In Ruby, I don't really see what purpose interfaces would have, or 
what they would enable me to do. I much prefer the implicit duck-typing 
interfaces. If it's a situation where I need an explicit interface as 
documentation, I think documentation works well enough.