Interfaces in Ruby

hi all and a happy new year!

i’m currently getting to know ruby. i like all that i have seen so far and
especially comparing ruby and perl it has major advantages (clean oo being
the most important imho).

since ruby is dynamically type in principle there is no technical need for
interfaces. however, if i want to define an interface - say for reasons of
documentation - what is the suggested way to do so? create a class with a
set of methods returning ‘nil’ or ‘self’? or create a method, that checks
the interface of an instance and raises a TypeError if any of the methods is
missing? what would you suggest?

thanks for some insights!

kind regards

robert

The latter is the approach I took on my most recent Ruby project. I
was pretty happy with it. These were abstract classes, not
interfaces (in Java parlance), but the point remains the same.

My exact code in the methods was:

raise "This method needs to be overwritten"

Cheers,
Gavin

···

On Friday, January 3, 2003, 1:49:55 AM, Robert wrote:

since ruby is dynamically type in principle there is no technical need for
interfaces. however, if i want to define an interface - say for reasons of
documentation - what is the suggested way to do so? create a class with a
set of methods returning ‘nil’ or ‘self’? or create a method, that checks
the interface of an instance and raises a TypeError if any of the methods is
missing? what would you suggest?

Make sure whatever mechanism you use is a module and not a class. Ruby
only has single inheritance, so if it’s a class, then I can’t get both
your interface and inherit from another class.

See some discussion on this at (at the bottom under Abstract Base
Classes):

http://www.rubygarden.org/ruby?RubyFromCpp

See also an earlier thread on this list starting at [ruby-talk:53297].

Paul

···

On Thu, Jan 02, 2003 at 11:49:55PM +0900, Robert wrote:

since ruby is dynamically type in principle there is no technical need for
interfaces. however, if i want to define an interface - say for reasons of
documentation - what is the suggested way to do so? create a class with a
set of methods returning ‘nil’ or ‘self’? or create a method, that checks
the interface of an instance and raises a TypeError if any of the methods is
missing? what would you suggest?

thanks a lot for those remarks and pointers!

kind regards

robert

“Paul Brannan” pbrannan@atdesk.com schrieb im Newsbeitrag
news:20030102160633.GS31857@atdesk.com

since ruby is dynamically type in principle there is no technical need
for
interfaces. however, if i want to define an interface - say for reasons
of
documentation - what is the suggested way to do so? create a class with
a
set of methods returning ‘nil’ or ‘self’? or create a method, that
checks
the interface of an instance and raises a TypeError if any of the
methods is

···

On Thu, Jan 02, 2003 at 11:49:55PM +0900, Robert wrote:

missing? what would you suggest?

Make sure whatever mechanism you use is a module and not a class. Ruby
only has single inheritance, so if it’s a class, then I can’t get both
your interface and inherit from another class.

See some discussion on this at (at the bottom under Abstract Base
Classes):

http://www.rubygarden.org/ruby?RubyFromCpp

See also an earlier thread on this list starting at [ruby-talk:53297].

Paul

Hi all,

in order to clarify my understanding of the issue at hand I tried to
summarize the discussion. Comments are welcome.

Interfaces in Ruby - the short story.

There are none.

Ok, since this was quite short, we’ll try a bit harder. :slight_smile:

Interfaces in Ruby - the real story.

Technically speaking Ruby does not need interfaces since it is dynamically
typed. Any argument list that at least satisfies the arity condition can be
handed into a method.

Since people appreciate the usage of interfaces and even more Design by
Contract (DbC) some mechanics were developed that mimic interfaces and
certain aspects of DbC. I list them in order of increasing complexity.

(1) Document which methods a method argument must implement or its expected
type.

(2) Define a module containing the methods that all raise an exception like
this:

module FooInterface
def bar(a,b) raise “bar(a,b) must be overridden”; end
end

class FooClass
include FooInterface

def bar(a,b) a+b; end
end

(3) Create a framework (like the one Paul Brannan suggested here [1]) for
defining interface methods and for checking that a particular instance
implements these methods.

(4) Try to support even more of DbC by dealing with preconditions and
postconditions like I tried in [2].

However: these things tend to get complicated and ugly, which seems to be
quite un-rubyish. Apart from that, they never reach the robustness and
power of languages with such features built in (like Eiffel).

From the perspective of an Eiffel developer this might not be satisfactory.
But then, one should keep in mind the different focus of Ruby. OO
capabilities are still a lot better than in Perl.

Regards

robert

[1]
http://rm-f.net/~cout/code/ruby/treasures/RubyTreasures-0.3/lib/hacks/interf
ace.rb.html

[2] Imperfect DbC experiments:

class ConditionException < Exception; end
class PreConditionException < ConditionException; end
class PostConditionException < ConditionException; end

module Contract
def type_check(value, type)
raise TypeError, “#{value} is not #{type}” unless value.kind_of? type
end

def pre_condition_check(binding, *predicates)
predicates.each do |p|
raise PreConditionException, “violation of ‘#{p.strip}’” unless
eval(p, binding)
end
end

def post_condition_check(binding, *predicates)
predicates.each do |p|
raise PostConditionException, “violation of ‘#{p.strip}’” unless
eval(p, binding)
end
end
end

module FooContract
include Contract

def bar(a,b)
# check preconditions
env = binding()

type_check(a, String)
type_check(b, Integer)

pre_condition_check env, %{ a.length < 10 }, %{ a.length > 0 }

# invoke method
result = barImpl(a,b)

# check postconditions
env = binding()

type_check(result, Array)
post_condition_check env, %{ result.size == 3 }

# finished
return result

end
end

class FooImpl
include FooContract

protected
def barImpl(a,b) [a, b, a*b]; end
end

foo = FooImpl.new

f.bar(“x”,3)

begin
f.bar(“x”,“3”)
rescue Exception => e
p e
end

begin
f.bar(“xxxxxxxxxxx”,3)
rescue Exception => e
p e
end

begin
f.bar("",3)
rescue Exception => e
p e
end

Good Summary … I’d like to add a few comments.

There are several reasons people like interfaces (and DbC for that
matter) …

(a) They enable compile time static type checks.
(b) They document the intended behaviour

If (a) is your goal, then Ruby is probably the wrong platform. There
has been much discussion of this issue in the past (check the archives),
and I’m not willing to take this thread down that path (for the moment).

Point (b) is a worthy goal and I think it is interesting to pursue.

I’ve found that when doing Test-Driven-Design, the unit test cases
provide much the same information as an explicit interface (and
contract). Perhaps the documentation issue with interfaces can be
addressed in the test case.

Here’s an example …

module ImplementsFoo
def test_bar
result = @obj.bar(1,2)
assert something interesting about the result
end
def test_baz
assert_responds_to(@obj, :baz)
end
end

class TestFooImpl < Test::Unit::TestCase
include ImplementsFoo
def setup
@obj = FooImpl.new
end

def test_extra_stuff
  # Assert behaviour beyond basic Foo stuff
end

end

The “include ImplementsFoo” line in the FooImple test case not only
documents that FooImpl implements a Foo interface, it also assures us
that FooImpl actual behaves as a Foo is expected to behave.

All in all, I like this. The test case clearly documents that the
behavior of a Foo object is provided. It actually checks for that
behavior.

···

On Sun, 2003-01-05 at 10:17, Robert wrote:

in order to clarify my understanding of the issue at hand I tried to
summarize the discussion. Comments are welcome.


– Jim Weirich jweirich@one.net http://w3.one.net/~jweirich

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

(c) They permit reasonably watertight multiperson projects.

Test-driven design should be able to take care of that too.

martin

···

Jim Weirich jweirich@one.net wrote:

There are several reasons people like interfaces (and DbC for that
matter) …

(a) They enable compile time static type checks.
(b) They document the intended behaviour

“Jim Weirich” jweirich@one.net schrieb im Newsbeitrag
news:1041791431.8201.81.camel@traken…

in order to clarify my understanding of the issue at hand I tried to
summarize the discussion. Comments are welcome.

Good Summary …

thanks!

I’ve found that when doing Test-Driven-Design, the unit test cases
provide much the same information as an explicit interface (and
contract). Perhaps the documentation issue with interfaces can be
addressed in the test case.

or even more than this: maybe someone finds a way to integrate these.
wouldn’t it be nice if the part of the test that verifies the contract could
be reused in production code since it is essentially the same? or would
that bring in too much interference between test and the “real” code?

hm…

robert
···

On Sun, 2003-01-05 at 10:17, Robert wrote:

Isn’t (c) a restatement of (a)? Or is there something other than static
type checking that contributes to (c)?

···

On Sun, 2003-01-05 at 13:38, Martin DeMello wrote:

Jim Weirich jweirich@one.net wrote:

There are several reasons people like interfaces (and DbC for that
matter) …

(a) They enable compile time static type checks.
(b) They document the intended behaviour

(c) They permit reasonably watertight multiperson projects.


– Jim Weirich jweirich@one.net http://w3.one.net/~jweirich

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

Good Summary …

thanks!

:slight_smile:

I’ve found that when doing Test-Driven-Design, the unit test cases
provide much the same information as an explicit interface (and
contract). Perhaps the documentation issue with interfaces can be
addressed in the test case.

or even more than this: maybe someone finds a way to integrate these.
wouldn’t it be nice if the part of the test that verifies the contract could
be reused in production code since it is essentially the same? or would
that bring in too much interference between test and the “real” code?

Are you advocating running the unit test in the runtime code? I’m not
sure this makes sense. For one thing, the unit test may modify the
object in the course of testing it (for example, a unit test might push
an item onto a stack to test the push method).

Although there is significant overlap between DbC and Unit Tests (UT),
there are still some basic differences. After I wrote EiffelUnit, I
published some thoughts on DbC and Unit Testing (I put the notes at
http://w3.one.net/~jweirich/talks/dbc-and-unittests.html).

In summary …

(1) DbC assertions check every call, but only when they are enabled.
UT only check during the unit test run.

(2) It is difficult to test for precondition correctness in UT.

(3) Both UT and DbC test postconditions. DbC expresses the
postcondition in general terms that must always be true. UT are
written against explicit and concrete situations designed in
the unit test.

···

On Mon, 2003-01-06 at 15:02, Robert wrote:


– Jim Weirich jweirich@one.net http://w3.one.net/~jweirich

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

Aren’t contracts distinct from static type checks?

martin

···

Jim Weirich jweirich@one.net wrote:

On Sun, 2003-01-05 at 13:38, Martin DeMello wrote:

Jim Weirich jweirich@one.net wrote:

There are several reasons people like interfaces (and DbC for that
matter) …

(a) They enable compile time static type checks.
(b) They document the intended behaviour

(c) They permit reasonably watertight multiperson projects.

Isn’t (c) a restatement of (a)? Or is there something other than static
type checking that contributes to (c)?

“Jim Weirich” jweirich@one.net schrieb im Newsbeitrag
news:1041904170.8193.117.camel@traken…

or even more than this: maybe someone finds a way to integrate these.
wouldn’t it be nice if the part of the test that verifies the contract
could
be reused in production code since it is essentially the same? or
would
that bring in too much interference between test and the “real” code?

Are you advocating running the unit test in the runtime code? I’m not
sure this makes sense. For one thing, the unit test may modify the
object in the course of testing it (for example, a unit test might push
an item onto a stack to test the push method).

no, i was just wondering whether it is reasonable to make the part of the
test that verifies the contract (i.e. method signatures) accessible for
production code. assuming we are talking about a class A, which has an
associated unit test T(A). my question was whether it might be possible
and reasonable to extract that part of T(A) that verifies the interface of
A. thus it could be made accessible to class B which uses A instances in
its method signatures.

but the longer i think about it the lesser i like that idea, especially
because of issue (2) you listed. i’ll have a look at you page and if i get
some new insights i let you know. thanks for your time!

regards

robert
···

Although there is significant overlap between DbC and Unit Tests (UT),
there are still some basic differences. After I wrote EiffelUnit, I
published some thoughts on DbC and Unit Testing (I put the notes at
http://w3.one.net/~jweirich/talks/dbc-and-unittests.html).

In summary …

(1) DbC assertions check every call, but only when they are enabled.
UT only check during the unit test run.

(2) It is difficult to test for precondition correctness in UT.

(3) Both UT and DbC test postconditions. DbC expresses the
postcondition in general terms that must always be true. UT are
written against explicit and concrete situations designed in
the unit test.


– Jim Weirich jweirich@one.net http://w3.one.net/~jweirich

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

Definitely, it is quite reasonable to do type checking at
run time - this is done quite a lot anyway.

When designing an API for someone else to use, it might be convenient
to have an easy way of specifying that an object supports all the
methods you need it to. In terms of duck typing, does it walk, quack,
fly and taste like a duck.

Maybe you wouldn’t even need to specify that a class implemented it -
it would implement it by virtue of walking, quacking and flying,
support the interface. If the user of your API didn’t pass an object
supporting everything a useful Exception could be thrown describing
the methods the object needs to support.

Of course, as with almost everything it would be fairly easy to
implement something like this without needing a language extension-
perhaps it would look like:

class MyInterface
methods :foo, :bar
end

class MyClass
def foo
end

  def bar
  end    

end

class MyClass2
def something_else
end
end

MyClass.new.implements(MyInterface) # => true
MyClass2.new.implements(MyInterface) # => false

-Tom

···

On Mon, Jan 06, 2003 at 05:18:50AM +0900, Martin DeMello wrote:

(c) They permit reasonably watertight multiperson projects.

Isn’t (c) a restatement of (a)? Or is there something other than static
type checking that contributes to (c)?

Aren’t contracts distinct from static type checks?

Oops … of course.

I mentioned contracts but then wrote (a) and (b) with interfaces in
mind. With contracts in mind, I think I would express (c) like this …

(c’) They validate that implementations provide the expected behaviour.

Which, of course, unit tests can accomplish as well.

···

On Sun, 2003-01-05 at 15:18, Martin DeMello wrote:

Jim Weirich jweirich@one.net wrote:

On Sun, 2003-01-05 at 13:38, Martin DeMello wrote:

Jim Weirich jweirich@one.net wrote:

There are several reasons people like interfaces (and DbC for that
matter) …

(a) They enable compile time static type checks.
(b) They document the intended behaviour

(c) They permit reasonably watertight multiperson projects.

Isn’t (c) a restatement of (a)? Or is there something other than static
type checking that contributes to (c)?

Aren’t contracts distinct from static type checks?


– Jim Weirich jweirich@one.net http://w3.one.net/~jweirich

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

“Robert Klemme” bob.news@gmx.net schrieb im Newsbeitrag
news:ave42g$em0fq$1@ID-52924.news.dfncis.de

but the longer i think about it the lesser i like that idea, especially
because of issue (2) you listed. i’ll have a look at you page and if i
get
some new insights i let you know. thanks for your time!

i read your article at
http://w3.one.net/~jweirich/talks/dbc-and-unittests.html and fully agree. i
always think that one important point (or maybe the most important point) of
DbC and unit testing is, that it forces you to think about what you expect
from the code you are going to write. the array resize is a nice example of
this: you could think of several different implementations that are all
reasonable among them versions that don’t even try to preserve old content.
but the version choosen behaves differently and this had to be decided on
and it is documented in the unit tests as well as in the postcondition.
(even if it lacks ease of understanding it surely makes clear that there is
something more complex going on as a simple resize.)

regards

robert