ruby abstraction

J

James O'Brien

[Note: parts of this message were removed to make it a legal post.]

Hi,

I'm a newbie with a background in Java. I've just about finished working
through an introductory ruby book and I didn't see anything about abstract
classes or indeed interfaces.

I have found the concept of an interface invaluable in my Java programming
and wondered if there were an equivalent concept in Ruby?

I'm open to the idea that interfaces might not be needed in Ruby but I'd
very much like this properly explained since as a thought-experiment I
propose Java without interfaces would be worse - therefore what is it
specifically about Ruby which means it is not as needed? I'm well versed in
the benefits of test driven code and documentation but we have this in Java
too (and still find interfaces a useful abstraction tool). So is there
something I'm missing or are interfaces something people here would like to
see added to the Ruby language? I agree Ruby is wonderful but loyalties
aside can someone actually put it in words for me why it doesn't need
interfaces.

many thanks for your replies
 
S

Steve Klabnik

[Note: parts of this message were removed to make it a legal post.]

There aren't interfaces in Ruby, because Ruby is dynamically typed. So
rather than see if an object is of the right type, you ask it if it responds
to a certain message, using Object#respond_to?

I'm open to the idea that interfaces might not be needed in Ruby but I'd
very much like this properly explained since as a thought-experiment I
propose Java without interfaces would be worse - therefore what is it
specifically about Ruby which means it is not as needed?


It comes down to the whole dynamic/static thing. Ruby's philosophy is 'screw
the types, does it do what you want or not?'
 
D

David Masover

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.
 
R

Robert Klemme

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.


Probably.

You could not have Java without interfaces. You would at least have to
drop static typing and this would be a major change to the language. I
don't think you would still call the result of this operation "Java".

Kind regards

robert
 
J

James O'Brien

[Note: parts of this message were removed to make it a legal post.]

David,

many thanks! i found your explanation very useful.. and an article on duck
typing is well worth reading e.g http://en.wikipedia.org/wiki/Duck_typing for
any other ruby newbies out there!


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.
 
R

Rick DeNatale

David,

many thanks! i found your explanation very useful.. and an article on duck
typing is well worth reading e.g http://en.wikipedia.org/wiki/Duck_typing for
any other ruby newbies out there!

FWIW, I wrote a paper about role-based 'types' nearly 20 years ago,
when I was at IBM. I've shared it with a few experienced Rubyists who
seemed to find a certain resonance with the ideas. Recently Alexander
Cockburn (of Crystal fame) with whom I have a shared hertitage at IBM
back then, tells me he still uses the paper when talking to clients
about dynamic typing.

http://talklikeaduck.denhaven2.com/files/TypesFromTheClientsViewpoint.PDF

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Github: http://github.com/rubyredrick
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
 
R

Robert Klemme

2010/7/19 Clifford Heath said:
Interfaces provide Java with dynamic method dispatch, without the
cost(*) of having every individual method in the dispatch table as
is the case with Ruby and other dynamic languages.

That sounds interesting. Can you please elaborate a bit more or
reference some documentation about this? Thanks!

Kind regards

robert
 
C

Clifford Heath

James said:
I have found the concept of an interface invaluable in my Java programming
and wondered if there were an equivalent concept in Ruby?
I'm open to the idea that interfaces might not be needed in Ruby

Interfaces provide Java with dynamic method dispatch, without the
cost(*) of having every individual method in the dispatch table as
is the case with Ruby and other dynamic languages. In other words,
Ruby has interfaces; every method is its own interface. If you want
to group those methods logically, you are free to (as long as you
don't use the same method name in two groups!).

Unlike Java, Ruby also allows new methods to be added at runtime.
That requires every method lookup to traverse the inheritance chain
in a linear fashion, instead of one dynamic lookup per dispatch.
Caching method lookups helps a bit, but the linear search is still
the main reason that Ruby's method dispatch is slower than Java's.

(*) It turns out that to search a method table is little to no more
costly than to search an interface table, so Java gains nothing there.

Clifford Heath.
 
R

Rick DeNatale

Interfaces provide Java with dynamic method dispatch, without the
cost(*) of having every individual method in the dispatch table as
is the case with Ruby and other dynamic languages. In other words,
Ruby has interfaces; every method is its own interface. If you want
to group those methods logically, you are free to (as long as you
don't use the same method name in two groups!).

Unlike Java, Ruby also allows new methods to be added at runtime.
That requires every method lookup to traverse the inheritance chain
in a linear fashion, instead of one dynamic lookup per dispatch.
Caching method lookups helps a bit, but the linear search is still
the main reason that Ruby's method dispatch is slower than Java's.

(*) It turns out that to search a method table is little to no more
costly than to search an interface table, so Java gains nothing there.

Is the * the equivalent of Emily Litella's "Never Mind!"
http://en.wikipedia.org/wiki/Emily_Litella

There's thirty or more years of experience in getting dynamic method
dispatch to run efficiently. Techniques such as polymorphic inline
caching, dynamic (re)compilation and others. One of the pioneers of
this work was David Ungar who analyzed Smalltalk performance as his
PhD dissertation, then spearheaded Self which was a language which
turned the dynamic lookup knob up to 11 (it did away with the
distinction between methods and instance variables) which exacerbates
the problems of having to do continuous dynamic lookups and found
techniques to make the language performant. Such techniques formed
the basis of the HotSpot JIT technology in Java.

There is a wealth of literature on efficient implementation of dynamic
languages, particularly in the proceedings of OOPSLA in the mid 1980s
forwards.

To date, the MRI implementations have used rather naive techniques.
JRuby does take advantage of JVM implementation techniques, albeit a
bit less directly than say MagLev which is built on a similarly
sophisticated VM which was engineered for Smalltalk rather than Ruby a
language whose underlying object model more closely maps to Ruby than
does Java.

Now, I'm far from an expert on JVM implementation, but the last time I
looked, it seemed that interfaces were really only used in method
dispatch as a way to provide the equivalent of what Ruby uses symbols
for. In ruby the method invocations

a.foo
a.foo(1)
a.foo("abc")

All resolve to the same method, where in Java these would be different
overloaded methods based on different types and numbers of parameters
(different signatures). So the combination of method name and
parameter type list needs to be mapped to a 'selector' of a method
defined in a particular (super)class or interface. The java bytecodes
to call a method typically involve fetching a 'token' from a class or
interface (which is known because of the type of the variable
'receiving' the call, and then calling a dispatch function with the
receiver, the token, and the argument values. This is very similar to
what happens in Ruby except that instead of a token based on the name
and parameter types, Ruby just uses the symbol form of the method
name.

What happens on the other side of the dispatch function is hidden, but
the effect is for the VM to find the right method implementation and
invoke it.

The traditional C++ implementation of virtual functions uses the
compiler's knowledge of the called object type and the class hierarchy
of that type to find a virtual function table and index that to find a
pointer to the method. This turns out to be very fragile, and is why
large C++ programs have LOTS more make dependencies than does a
typical C program, meaning that small source code changes can require
MANY files to be recompiled to make sure everyone has the right
locations of VFTs and virtual function indexes.

If you're interested in this try googling for "fragile base class
problem." This issue be-deviled those who tried to use C++ to build
"framework-based" OS APIs during the days of C++ fever.

http://talklikeaduck.denhaven2.com/2007/06/15/a-meeting-with-gill-bates *
http://talklikeaduck.denhaven2.com/2009/10/10/oh-the-irony

Another related bit of history is the war between different
semi-static/semi-dynamic "object models" like IBM's SOM vs.
Microsoft's COM *. Although I was playing for the "IBM team" I never
thought much of either to be honest.

http://en.wikipedia.org/wiki/IBM_System_Object_Model
http://en.wikipedia.org/wiki/Component_Object_Model


This approach falls down completely when the type hierarchy can change
at run-time and I'm pretty sure that most JVMs do the actual method
lookup more dynamically and use caching to achieve performance.

* BTW, Tony Williams who is considered as the co-inventor of COM was
IIRC the guy presenting in this meeting, and if he wasn't the
presenter he was in the room.

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Github: http://github.com/rubyredrick
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
 
D

David Masover

You could not have Java without interfaces. You would at least have to
drop static typing and this would be a major change to the language. I
don't think you would still call the result of this operation "Java".

I don't think so. It would be much like Java without Generics -- frustrating
to work with, but possible. Basically, it kills any sort of polymorphism
between things which don't share a common ancestor -- so you make more use of
inheritance in some situations (take Collections, it wouldn't be so bad if we
had to inherit from AbstractCollection, AbstractList, etc), and aggressively
abuse modular decomposition (anywhere you have one object that needs to
pretend to be two types, make two related objects!), and you could make it
work.

In fact, IIRC, this is how C++ does it -- it's just made much easier due to
multiple inheritance. I never quite understood why Java allows multiple
interfaces to be applied to the same object, and even to the same interface,
but not multiple inheritance.

I'm not suggesting this would be a good idea, mind you -- but then, I'm also
not entirely sure either Java or C++ is a good idea.
 
D

David Masover

FWIW, I wrote a paper about role-based 'types' nearly 20 years ago,
when I was at IBM. I've shared it with a few experienced Rubyists who
seemed to find a certain resonance with the ideas. Recently Alexander
Cockburn (of Crystal fame) with whom I have a shared hertitage at IBM
back then, tells me he still uses the paper when talking to clients
about dynamic typing.

http://talklikeaduck.denhaven2.com/files/TypesFromTheClientsViewpoint.PDF

Definitely a resonance.

If I understand what you're saying, something like Java interfaces were known
and implemented in C++ and Smalltalk, though more by convention. I wonder if
client-side interfaces were ever implemented as anything quite so explicit...

I wish I'd known about this earlier. In a Java-based freshman data structures
course, a TA asked an interesting question: "What is the purpose of
inheritance?" I answered, "Code re-use." He disagreed, and I'm not entirely
sure, but I think he said, "Types." In Java! Ah, well...
 
R

Robert Klemme

Definitely a resonance.

If I understand what you're saying, something like Java interfaces were known
and implemented in C++ and Smalltalk, though more by convention. I wonder if
client-side interfaces were ever implemented as anything quite so explicit...

There once was the concept of "signature" in g++. Basically you could
retrofit any "interface" as a signature to any class (or even type, I
don't exactly remember). The concept was pretty cool but at some point
they kicked it out. I guess it was too infrequently used and / or
caused too much hassle for the compiler implementation.
I wish I'd known about this earlier. In a Java-based freshman data structures
course, a TA asked an interesting question: "What is the purpose of
inheritance?" I answered, "Code re-use." He disagreed, and I'm not entirely
sure, but I think he said, "Types." In Java! Ah, well...

OOSC lists several purposes and Betrand Meyer would heavily agree to you
that code reuse is a major reason for inheritance ("implementation
inheritance"). So he made Eiffel one of the few OO (the only?)
languages in which not every inheritance relationship is a "is a"
relationship. Quite interesting stuff. I really should read it again -
if only time permitted...

Kind regards

robert
 
R

Robert Klemme

I don't think so. It would be much like Java without Generics -- frustrating
to work with, but possible. Basically, it kills any sort of polymorphism
between things which don't share a common ancestor -- so you make more use of
inheritance in some situations (take Collections, it wouldn't be so bad if we
had to inherit from AbstractCollection, AbstractList, etc), and aggressively
abuse modular decomposition (anywhere you have one object that needs to
pretend to be two types, make two related objects!), and you could make it
work.

Still, that would not be the Java for me that we have today. Without
interface a major feature for structuring code would be gone.
Expressiveness of the language would be significantly changed. But you
are right the language would resemble today's Java pretty much.
In fact, IIRC, this is how C++ does it -- it's just made much easier due to
multiple inheritance. I never quite understood why Java allows multiple
interfaces to be applied to the same object, and even to the same interface,
but not multiple inheritance.

State. I guess they were afraid of the way C++ makes inheritance
complicated because of virtual and non virtual inheritance and the
consequences for the visibility of state ("diamond problem"). I would
also add that "interface" is a cleaner concept because it stresses the
fact that not behavior or state is shared but only the interface.
Granted, you can achieve similar goals with abstract classes that
contain only abstract methods but I think it was wise do have interfaces
in Java.
I'm not suggesting this would be a good idea, mind you -- but then, I'm also
not entirely sure either Java or C++ is a good idea.

LOL

Cheers

robert
 
R

Robert Klemme

Because every object which implements an expected interface may have
a different set of other interfaces, it requires a dynamic lookup
to find the right one. Typically there are many fewer interfaces
than methods of course, so the search is cheaper that way.

Wouldn't that mean duplicate entries for a method which is part of
several interfaces? And what happens in case of interface inheritance?
Of course, there are many ways to optimise it, as Rick pointed out.
Excellent paper, Rick, I enjoyed it.

Same here. :)

Kind regards

robert
 
C

Clifford Heath

Robert said:
That sounds interesting. Can you please elaborate a bit more

Because every object which implements an expected interface may have
a different set of other interfaces, it requires a dynamic lookup
to find the right one. Typically there are many fewer interfaces
than methods of course, so the search is cheaper that way.

Of course, there are many ways to optimise it, as Rick pointed out.
Excellent paper, Rick, I enjoyed it.

Clifford Heath.
 
C

Clifford Heath

Robert said:
Wouldn't that mean duplicate entries for a method which is part of
several interfaces?

Yes, but the compiler knows which interface it wants,
so there's no ambiguity. Dynamic binding only occurs
at the interface level. Once you have the interface,
getting the method is just a table lookup.
And what happens in case of interface inheritance?

Each interface requires a single set of methods, whether
through declaration or inheritance, so there's no need
for a special case.

Clifford Heath.
 
D

David Masover

State. I guess they were afraid of the way C++ makes inheritance
complicated because of virtual and non virtual inheritance and the
consequences for the visibility of state ("diamond problem").

It seems like this exact problem exists just as much in an interface, though
-- the only difference is that interfaces force implementations to explicitly
implement each of their methods. The simple solution, then, would be to force
the inheriting class to explicitly override those methods.

Actual, direct state -- as in, instance variables -- I don't see any reason
for an instance variable to be anything other than private, except for the
fact that Java makes setters and getters ridiculously verbose.
I would
also add that "interface" is a cleaner concept because it stresses the
fact that not behavior or state is shared but only the interface.

I agree that it's cleaner, but it's also something which could easily be done
by convention, as you suggest:
Granted, you can achieve similar goals with abstract classes that
contain only abstract methods

A Java Interface is essentially an abstract class, which contains only
abstract methods, but which can be multiply inherited from.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top