Interfaces in Ruby

Fair enough. Still it bothers me that classes are `branded’ with a
mark that says something about the author, not them. (And one is
easily mistaken into thinking the other way round.)

Massimiliano

···

On Fri, Oct 18, 2002 at 10:42:05PM +0900, Paul Brannan wrote:

Second, is certifying a behaviour really a class’s responsibility?

The intent of an interface is not to cerfity a particular behavior. It
is to certify that the author’s intent is for the class to have a
particular behavior.

Paul Brannan wrote:

Second, is certifying a behaviour really a class’s responsibility?

The intent of an interface is not to cerfity a particular behavior. It
is to certify that the author’s intent is for the class to have a
particular behavior.

This is true of Java interfaces, but Design By Contract does make
certifying a particular behavior a class’ responsibility, which is why I
think it’s a misnomer for the Java literature to refer to interfaces as
contracts. It’s like a business contract that only lists the names of the
parties involved and doesn’t state their obligations and benefits.

“Some day” I’m going to have to create an experimental language that,
going one step beyond Eiffel, reifies contracts and makes them first-class
language citizens. Perhaps Ruby’s metaprogramming facilities would be
enough to toy around with this idea. If not, it could probably be done in
Lisp.

···

On Fri, Oct 18, 2002 at 08:13:18PM +0900, Massimiliano Mirra wrote:


Jason Voegele
“We believe that we invent symbols. The truth is that they invent us.”
– Gene Wolfe, The Book of the New Sun

Isn’t that the point of comments and/or documentation. I’d argue that
if the only point of an interface is to act as a comment, then it should
be left as as a comment.

Regards,
Nat.

···

On Fri, 2002-10-18 at 14:42, Paul Brannan wrote:

The intent of an interface is not to cerfity a particular behavior. It
is to certify that the author’s intent is for the class to have a
particular behavior.


Dr. Nathaniel Pryce, Technical Director, B13media Ltd.
Studio 3a, 22-24 Highbury Grove, London N5 2EA, UK
http://www.b13media.com

> The intent of an interface is not to cerfity a particular behavior. It > is to certify that the author's intent is for the class to have a > particular behavior. > > Paul

There is no way to certify that an author’s intent is reflected in his code.
Isn’t this called a bug?

···

On Friday 18 October 2002 1:42 pm, Paul Brannan wrote:


Best essay I’ve read in years:
http://www.spack.org/words/commandline.html

“Chris Gehlker” canyonrat@mac.com schrieb im Newsbeitrag
news:CACB6AEA-E176-11D6-A92E-000A27DA50C4@mac.com

There is no need to enforce the use of the factory method. What needs
to be enforced is that the program cannot instantiate an instance of
the cluster base class. This corresponds directly to the C++ case where
their is no enforcement of a restriction on directly constructing a
derived concrete class but there is enforcement of the “no
instantiation of virtual classes” rule.

  1. Having a private constructor in Ruby doesn’t make sense; this is
    the purpose of a Module (you can always instantiate a Class, but
    you can’t always instantiate a Module)

Having a private constructor makes sense for cluster base classes and
singleton classes.

Perhaps if you provide a sample implementation it would be easier to

I’ll try and translate my drawing program from ObjC to Ruby.

suggestion:

class Shape
def move … end
def resize … end
def bounding_rectangle() … end

private
def initialize() raise “Cannot instantiate”; end

def init()
  # initializations
end

end

class Rectangle < Shape
private
def initialize()
# don’t ‘super’ here but:
init()
end

def init()
  super
  # other initializations
end

end

regards

robert

Weak typing allows the code to work on any object though. In Eiffel, the
code you mixin, must then be generic enough to not have type conflicts with
the code in the object being mixed into… Right? In Java, there was no
safe way to allow that to happen. Java interfaces are kind of like
glorified type specifies that you mix in and that the compiler enforces.

Thanks,

Sam

···

On 10/16/2002 10:46 PM, in article 1034826513.31505.29.camel@traken, “Jim Weirich” jweirich@one.net wrote:

On Wed, 2002-10-16 at 22:05, Sam Griffith wrote:

The fact that you can inherit default implementations is also something that
makes Ruby’s mixin’s more powerful than Java’s interfaces. And it is also a
point for weak typing. The reason you can’t have Java interfaces provide
default implementations is the strong typing.

The reason you can’t have Java interfaces provide implementation has
less to do with strong typing and more to do with Java’s disdain for
multiple inheritance. I mix-in implementation in Eiffel all the time,
and Eiffel is more strongly typed than Java.

I don’t agree that an interface, in the Java sense, and an abstract
class, in the Java/C++ sense are synonymous

An abstract class in C++, with all pure virtual methods and no data, is
semantically equivalent to a Java interface[1]. They are often used in
C++ programs in ways similar to Java interfaces.

Yes it is. In that case, they are functionally equivalent.

There are also:
3) Idiosyncratic but very clever uses as, for example, in the STL,
where it is somewhat obscured by all the template stuff, and in
GNUStep
where it isn’t.

I’m not sure what you are refering to here, but it sounds interesting.
Examples?

In GNUStep, for example, GSArray and GSMutableArray are never actually
instantiated even though they are foundation types. What gets returned
from the constr is a pointer to some specific type depending on the
size and number of elements. Some of the methods in GSMutableArray
actually return a pointer to a different member of the class cluster
than the original receiver of the message, which constructs the sibling
instance, copies it’s data and immolates itself. All this stuff is
going on behind the scenes in the interest of faster execution speed.
As a user, you just don’t have to think about it.

I’ll try and translate my drawing program [with class cluster
examples] >
from ObjC to Ruby.

I, too, am interested in seeing this.

I’ll get busy.

···

On Wednesday, October 16, 2002, at 09:29 PM, Jim Weirich wrote:

On Wed, 2002-10-16 at 22:19, Chris Gehlker wrote:


As an adolescent I aspired to lasting fame, I craved factual certainty,
and I thirsted for a meaningful vision of human life - so I became a
scientist. This is like becoming an archbishop so you can meet girls.
-Matt Cartmill, anthropology professor and author (1943- )

The goals behind an interface or abstract class are:

  1. Be able to write a function that can take as a parameter any
    object that inherits from the abstract class (generic
    programming).

I don’t agree that an interface, in the Java sense, and an abstract
class, in the Java/C++ sense are synonymous or that an interface has
necessary relationship to generic programming. Generic programming
came
out of C++, which has no notion of interface.

I think I was mistaken to call this “generic programming,” which is
similar but different. Must have been too much sugar after lunch. :slight_smile:
I think the correct word is “polymorphism.”

Aha

I believe the most common uses of the abstract class are:

  1. To provide code clarity and to avoid code duplication

I can agree that abstract classes can help provide clarity. I don’t
see
how they avoid code duplication, since pure abstract base classes are
not supposed to have any implementation.

It’s actually the impure ones that centralize methods and data common
to all their children in one place.

  1. To provide a way of referencing an object who’s type is not
    determined until run time, for example, the elements of a display list
    in a drawing program.

This also falls under polymorphism.

There are also:
3) Idiosyncratic but very clever uses as, for example, in the STL,
where it is somewhat obscured by all the template stuff, and in
GNUStep
where it isn’t.

Motivation 2 disappears in dynamic langaguages. 1 and 3 remain.

I can’t think of a case in Ruby where #3 would apply.

Maybe I can. Remember all the discussion of string and how some users
can’t even represent their own name? I can envision some future version
of Ruby making string a class cluster and making “string” the cluster
base as a common interface to “ascii_string”, “UTF8_string”,
“unicode32_string”, etc. This might be done in such a way that existing
code would only take a minor performance hit but strings methods would
automagically work for richer encoding schemes.

There is no need to enforce the use of the factory method. What needs
to be enforced is that the program cannot instantiate an instance of
the cluster base class. This corresponds directly to the C++ case
where
their is no enforcement of a restriction on directly constructing a
derived concrete class but there is enforcement of the “no
instantiation of virtual classes” rule.

In Ruby, if the base class has implementation, I would almost certainly
throw it into a Module, because you cannot instantiate a Module. If it
has no implementation (the “Toy” abstract base class in the wiki link
above), then I generally remove it completely.

What would keep you from turning your cluster base class into a Module,
and using it as a mixin?

Because the ‘is a’ relationship is going the opposite direction. I use
Modules in Ruby where I would use MI in C++ and cluster bases where I
would use virtual classes. That way I have a nice clean inheritance
tree.

···

On Thursday, October 17, 2002, at 07:55 AM, Paul Brannan wrote:

On Thu, Oct 17, 2002 at 11:19:04AM +0900, Chris Gehlker wrote:


There are two kinds of fool. One says, “This is old, and therefore
good.”
And one says, “This is new, and therefore better.”
-John Brunner, science fiction writer (1934-1995)

There are some days that I agree.

There are other days when I feel that it would be useful to
programatically determine what the author’s intent was for a class.
This is something that is difficult to do with comments alone.

Paul

···

On Fri, Oct 18, 2002 at 11:20:43PM +0900, Nat Pryce wrote:

On Fri, 2002-10-18 at 14:42, Paul Brannan wrote:

The intent of an interface is not to cerfity a particular behavior. It
is to certify that the author’s intent is for the class to have a
particular behavior.

Isn’t that the point of comments and/or documentation. I’d argue that
if the only point of an interface is to act as a comment, then it should
be left as as a comment.

“Reify” is a word I had encountered once. In a dictionary. Becuase someone
pointed it out as a funny/cool word. It’s good to see it in use. I had to
look it up again. For those interested, it means:

Convert (a concept etc.) mentally into a thing; materialize.

Keep up the good work.

Gavin

···

----- Original Message -----
From: “Jason Voegele” jason@jvoegele.com

“Some day” I’m going to have to create an experimental language that,
going one step beyond Eiffel, reifies contracts and makes them first-class
language citizens. Perhaps Ruby’s metaprogramming facilities would be
enough to toy around with this idea. If not, it could probably be done in
Lisp.

Jason Voegele

Its not type conflicts that you worry about, but name conflicts. And
Eiffel has an elegant way of dealing dealing with name conflicts. For
example, the Enumerable mixin in Ruby would be quite doable in Eiffel as
well.

···

On Thu, 2002-10-17 at 01:06, Sam Griffith wrote:

Weak typing allows the code to work on any object though. In Eiffel, the
code you mixin, must then be generic enough to not have type conflicts with
the code in the object being mixed into… Right?


– 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)

module Foo1
end

class Bar1
include Foo1
end

b = Bar1.new
p b.is_a?(Foo1) #=> true

class Foo2
end

class Bar2 < Foo2
end

b = Bar2.new
p b.is_a?(Foo2) #=> true

The “is a” relationship looks to me like it’s going the same direction
in both cases.

Paul

···

On Fri, Oct 18, 2002 at 03:02:53AM +0900, Chris Gehlker wrote:

What would keep you from turning your cluster base class into a Module,
and using it as a mixin?

Because the ‘is a’ relationship is going the opposite direction. I use
Modules in Ruby where I would use MI in C++ and cluster bases where I
would use virtual classes. That way I have a nice clean inheritance
tree.

That’s true, but interfaces don’t help you, and DbC only gets you part
way there. Also, in my experience, DbC ends up polluting the class
interface with a lot of predicates, because it doesn’t support the idea
of protocols, and makes changing code very difficult because contracts
are duplicated throughout the code. Something similar to type inference
might help in the latter case.

Cheers,
Nat.

···

On Fri, 2002-10-18 at 18:03, Paul Brannan wrote:

On Fri, Oct 18, 2002 at 11:20:43PM +0900, Nat Pryce wrote:

On Fri, 2002-10-18 at 14:42, Paul Brannan wrote:

The intent of an interface is not to cerfity a particular behavior. It
is to certify that the author’s intent is for the class to have a
particular behavior.

Isn’t that the point of comments and/or documentation. I’d argue that
if the only point of an interface is to act as a comment, then it should
be left as as a comment.

There are some days that I agree.

There are other days when I feel that it would be useful to
programatically determine what the author’s intent was for a class.
This is something that is difficult to do with comments alone.


Dr. Nathaniel Pryce, Technical Director, B13media Ltd.
Studio 3a, 22-24 Highbury Grove, London N5 2EA, UK
http://www.b13media.com

Isn’t it nice to find Latin here and there?
“thingify” :wink:

···

On Sun, Oct 20, 2002 at 08:42:20PM +0900, Gavin Sinclair wrote:

----- Original Message -----
From: “Jason Voegele” jason@jvoegele.com

“Some day” I’m going to have to create an experimental language that,
going one step beyond Eiffel, reifies contracts and makes them first-class
language citizens. Perhaps Ruby’s metaprogramming facilities would be
enough to toy around with this idea. If not, it could probably be done in
Lisp.

Jason Voegele

“Reify” is a word I had encountered once. In a dictionary. Becuase someone
pointed it out as a funny/cool word. It’s good to see it in use. I had to
look it up again. For those interested, it means:

Convert (a concept etc.) mentally into a thing; materialize.


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Why are there always boycotts? Shouldn’t there be girlcotts too?
– argon on #Linux

What would keep you from turning your cluster base class into a
Module,
and using it as a mixin?

Because the ‘is a’ relationship is going the opposite direction. I use
Modules in Ruby where I would use MI in C++ and cluster bases where I
would use virtual classes. That way I have a nice clean inheritance
tree.

module Foo1
end

class Bar1
include Foo1
end

b = Bar1.new
p b.is_a?(Foo1) #=> true

class Foo2
end

class Bar2 < Foo2
end

b = Bar2.new
p b.is_a?(Foo2) #=> true

The “is a” relationship looks to me like it’s going the same direction
in both cases.

All I can say is “look again.” In the first example, the class is
inheriting from the module, not the other way around. Let me try to
draw it. My arrows go from the parent to the child, that is,
anti-Stroustrup.

Example 1


Object | | Foo1 |
-------- |_______|
>
\ /
\ /
\ /
\ /
\ /
\ /
\ /
\ /
\ /

            V
···

On Thursday, October 17, 2002, at 12:26 PM, Paul Brannan wrote:

On Fri, Oct 18, 2002 at 03:02:53AM +0900, Chris Gehlker wrote:
-------
Bar1 |
-------

Example 2

-----------
> Object  |
-----------
     >
     V
-----------
> Foo2    |
-----------
     >
     V
-----------
> Bar2    |
-----------

Virtual Class / Class Cluster Example
------------
> Object |
------------
>
V
------------------
> Cluster/Virtual |
> Base Class |
-------------------
>
/|
/ |
/ |
/ |
/ |
/ |
/ |
/ |
/ |
/ |
/ |
/ |
> > >
V V V
--------- ---------- ---------
> Child1 | | Child2 | | Child3 |
---------- ----------- ----------

Hope that helps

Cogito Ergo Spud. - I think therefore I yam.

[…] Also, in my experience, DbC ends up polluting the class
interface with a lot of predicates, because it doesn’t support the idea
of protocols, […]

I’m not sure I understand the above comment.

[…] and makes changing code very difficult because contracts
are duplicated throughout the code.

Really? In my experiance, the contract normally gets specified in the
most abstract class, and there is little need to repeat it. Subclasses
only express modifications and refinements to the contracts they
inherit.

···

On Fri, 2002-10-18 at 14:08, Nat Pryce 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)

I think your diagram here is slightly off. Ruby has only single
inheritance; there is no multiple inheritance, even if mixins give the
illusion of (and often advantages of) MI. In this example, Bar1
inherits from a proxy class Foo1’ which inherits from Object. To
illustrate this better:

class Base
def foo
puts “Base”
end
end

module M1
def foo
puts “M1”
super
end
end

module M2
def foo
puts “M2”
super
end
end

class Derived < Base
include M1
include M2
def foo
puts “Derived”
super
end
end

d = Derived.new
d.foo #=> Derived
M2
M1
Base

See also [ruby-talk:03591].

Paul

···

On Fri, Oct 18, 2002 at 11:57:40AM +0900, Chris Gehlker wrote:

Example 1


Object | | Foo1 |
-------- |_______|
>
\ /
\ /
\ /
\ /
\ /
\ /
\ /
\ /
\ /

           V 
        ------- 
        > Bar1 | 
        -------

[…] Also, in my experience, DbC ends up polluting the class
interface with a lot of predicates, because it doesn’t support the idea
of protocols, […]

I’m not sure I understand the above comment.

Often, when designing classes you define a protocol by which calls can
be made to the object. A simple example, a Socket object has methods to
connect, read and write data, shutdown the read or write stream, or
close both streams. You must call connect before calling read, write,
shutdown or close. Once you’ve called close, you cannot call read or
write again until you call connect again. Once you’ve shutdown the read
stream you cannot read, and similarly for write shutdown.

Client code that uses a socket keeps track of the socket state by its
own control flow. A socket can only be in a closed state if it has been
closed by the client code (ignoring errors in this example).

However, to specify this protocol in DbC you have to define
preconditions on whether the socket is open, and those preconditions
have to be defined in terms of public methods. E.g. the read method
might be:

read : BYTE is
        -- read a byte from the stream
    require
        is_open_for_read
    do
        -- blah blah blah
    ensure
        (is_open_for_read and result >= 0 and result < 255) or
        (not is_open_for_read and result == -1)
    end

is_open_for_read : BOOLEAN
– a predicate that tests whether the stream is open
– for reading

So you end up adding predicates to the public API of objects to track
the progress of the protocols used to interact with those object. Often
this also requires adding data members to keep track of the current
state of the object.

[…] and makes changing code very difficult because contracts
are duplicated throughout the code.

Really? In my experience, the contract normally gets specified in the
most abstract class, and there is little need to repeat it. Subclasses
only express modifications and refinements to the contracts they
inherit.

I found that when writing code that had a lot of composition, rather
than inheritance, contracts of classes would end up mirrored in the
interface of other classes that contained them, and in containers of
containers, and so on. If you changed the contract of a component
class, then the change would ripple through the containers. In very
compositional code, it became quite expensive to change contracts.

Cheers,
Nat.

···

On Sun, 2002-10-20 at 04:12, Jim Weirich wrote:

On Fri, 2002-10-18 at 14:08, Nat Pryce wrote:


Dr. Nathaniel Pryce, Technical Director, B13media Ltd.
Studio 3a, 22-24 Highbury Grove, London N5 2EA, UK
http://www.b13media.com

Example 1


Object | | Foo1 |
-------- |_______|
>
\ /
\ /
\ /
\ /
\ /
\ /
\ /
\ /
\ /

           V
        -------
        > Bar1 |
        -------

I think your diagram here is slightly off. Ruby has only single
inheritance; there is no multiple inheritance, even if mixins give the
illusion of (and often advantages of) MI.

I consider mixins to be a form of MI. I would go so far as to say
that it is the only form that I’ve actually seen usefully employed even
in C++ code. Your example below and your previous example with is_a
show that it passes the duck test. But even if you want to consider the
it to be “the illusion of multiple inheritance” it’s important to
maintain the illusion. Which is why I think it important to use class
clusters as well as mix-ins.

···

On Friday, October 18, 2002, at 06:36 AM, Paul Brannan wrote:

On Fri, Oct 18, 2002 at 11:57:40AM +0900, Chris Gehlker wrote:

In this example, Bar1
inherits from a proxy class Foo1’ which inherits from Object. To
illustrate this better:

class Base
def foo
puts “Base”
end
end

module M1
def foo
puts “M1”
super
end
end

module M2
def foo
puts “M2”
super
end
end

class Derived < Base
include M1
include M2
def foo
puts “Derived”
super
end
end

d = Derived.new
d.foo #=> Derived
M2
M1
Base

See also [ruby-talk:03591].

Paul


There are two kinds of fool. One says, “This is old, and therefore
good.”
And one says, “This is new, and therefore better.”
-John Brunner, science fiction writer (1934-1995)

Nat Pryce wrote:

[…] Also, in my experience, DbC ends up polluting the class
interface with a lot of predicates, because it doesn’t support the
idea of protocols, […]

I’m not sure I understand the above comment.

Often, when designing classes you define a protocol by which calls can
be made to the object. A simple example, a Socket object has methods to
connect, read and write data, shutdown the read or write stream, or
close both streams. You must call connect before calling read, write,
shutdown or close. Once you’ve called close, you cannot call read or
write again until you call connect again. Once you’ve shutdown the read
stream you cannot read, and similarly for write shutdown.
[snip]
However, to specify this protocol in DbC you have to define
preconditions on whether the socket is open, and those preconditions
have to be defined in terms of public methods.
[snip code example]
So you end up adding predicates to the public API of objects to track
the progress of the protocols used to interact with those object. Often
this also requires adding data members to keep track of the current
state of the object.

This is all true, but consider what you must do when you don’t use Design
By Contract. Either you 1) check the constraints within each method (e.g.
“defensive programming”) or 2) you leave it up to clients to enforce
consistency.

Option number 2 obviously leaves a lot to be desired.

Option number 1 suffers from the same drawbacks you mentioned for DBC,
i.e. you still have to keep track of the state of the object to ensure
consistency. In addition to these drawbacks, you lose all the things that
DBC can provide for you:

  1. Automatic checking of preconditions, postconditions, and invariants
    when run-time checking is enabled

  2. Automatic and controlled inheritance of assertions

  3. Automatic documentation of consistency constraints

  4. Clear delineation of responsibilities

  5. Reduced error-handling code

I don’t see what an ad-hoc solution can provide that outweighs these
benefits. Basically, the way I see it, by not using DBC, you end up
manually recreating a lot of it.

I found that when writing code that had a lot of composition, rather
than inheritance, contracts of classes would end up mirrored in the
interface of other classes that contained them, and in containers of
containers, and so on. If you changed the contract of a component
class, then the change would ripple through the containers. In very
compositional code, it became quite expensive to change contracts.

Interesting point. Perhaps this is why Eiffel emphasizes inheritance so
much more than any other language.

···

On Sun, 2002-10-20 at 04:12, Jim Weirich wrote:

On Fri, 2002-10-18 at 14:08, Nat Pryce wrote:


Jason Voegele
“We believe that we invent symbols. The truth is that they invent us.”
– Gene Wolfe, The Book of the New Sun