Mixin vs. multiple inheritence

In ruby-talk:72013, matz wrote:

It’s like multiple inheritance vs mix-in. Sometimes restricted one
behave better than more general one.

						matz.

How are mix-in more restricted than multiple inheritance?

T. Onoma wrote:

How are mix-in more restricted than multiple inheritance?

There is non such thing as a diamond shape
mixin graph …

/Christoph

Actually, that’s not really true.

module A; end
module B; include A; end
module C; include A; end
class D; include B; include C; end

You can build as complicated a mixin graph as you can a MI graph. The
difference is that because mixins are modules, they don’t have their
own state, but instead parasitically use the state of the class into
which they are mixed. This eliminates the underlying issue with MI,
where there may be two instances (logically) of the class at the top
of the diamond.

Cheers

Dave

···

On Dec 3, 2003, at 5:46, Christoph wrote:

T. Onoma wrote:

How are mix-in more restricted than multiple inheritance?

There is non such thing as a diamond shape
mixin graph …

Mixins in Ruby always create a linear graph. Consider your example with
a method foo added to each class that prints the name of the class and
then calls foo in the base class:

module A; def foo; puts “A”; end; end
module B; include A; def foo; puts “B”; super; end; end
module C; include A; def foo; puts “C”; super; end; end
class D; include B; include C; def foo; puts “D”; super; end; end

D.new.foo

The resulting output is:

D
C
B
A

I know of no way to get C#foo to call A#foo here.

Paul

···

On Wed, Dec 03, 2003 at 11:51:22PM +0900, Dave Thomas wrote:

module A; end
module B; include A; end
module C; include A; end
class D; include B; include C; end

You can build as complicated a mixin graph as you can a MI graph. The
difference is that because mixins are modules, they don’t have their
own state, but instead parasitically use the state of the class into
which they are mixed. This eliminates the underlying issue with MI,
where there may be two instances (logically) of the class at the top
of the diamond.

“Dave Thomas” dave@pragprog.com schrieb im Newsbeitrag
news:267B6CF2-25A0-11D8-92F7-000A95676A62@pragprog.com

T. Onoma wrote:

How are mix-in more restricted than multiple inheritance?

There is non such thing as a diamond shape
mixin graph …

Actually, that’s not really true.

module A; end
module B; include A; end
module C; include A; end
class D; include B; include C; end

You can build as complicated a mixin graph as you can a MI graph. The
difference is that because mixins are modules, they don’t have their
own state, but instead parasitically use the state of the class into
which they are mixed.

U sure about that? Try this:

module B
def initialize
super
@foo = “bar”
end
end

class X
include B

def initialize
super
@bar = “foo”
end
end

p X.new.instance_variables

This eliminates the underlying issue with MI,
where there may be two instances (logically) of the class at the top
of the diamond.

The MI issue is eliminated by not using classes as scopes for instance
variables and not declaring instance variables: @foo denotes the same
variable, regardless which module uses it. In fact, super class methods
can easily access instance variables that are introduced further down the
inheritance hierarchy.

Kind regards

robert
···

On Dec 3, 2003, at 5:46, Christoph wrote:

You can build as complicated a mixin graph as you can a MI graph. The
difference is that because mixins are modules, they don’t have their
own state, but instead parasitically use the state of the class into
which they are mixed.

U sure about that? Try this:

p X.new.instance_variables

I think you misunderstood what Dave was saying. This prints [ “@foo”,
@bar” ]. That’s because the module and the class in which it is
included share the same state, exactly as Dave pointed out.

Paul

···

On Thu, Dec 04, 2003 at 02:37:06AM +0900, Robert Klemme wrote:

Yes. Doesn’t your example actually illustrate the point? The module B
uses an instance variable, but it is actually containing in the objects
of the class that mixes in B.

Anyway, to be honest the whole conversation is somewhat moot: it isn’t
really an issue of whether one solves another’s problems. Both work,
they do similar but not identical things, and each has a set of rules
you have to understand to use them.

Cheers

Dave

···

On Dec 3, 2003, at 11:37, Robert Klemme wrote:

You can build as complicated a mixin graph as you can a MI graph. The
difference is that because mixins are modules, they don’t have their
own state, but instead parasitically use the state of the class into
which they are mixed.

U sure about that?

What you say is true enough. But I am wondering what it is that supposedly
Mutiple-in gives you that Mix-in does not, which was implied by matz, albiet
that the it is better Ruby’s way.

T.

···

On Wednesday 03 December 2003 06:53 pm, Dave Thomas wrote:

Anyway, to be honest the whole conversation is somewhat moot: it isn’t
really an issue of whether one solves another’s problems. Both work,
they do similar but not identical things, and each has a set of rules
you have to understand to use them.

“Paul Brannan” pbrannan@atdesk.com schrieb im Newsbeitrag
news:20031203174412.GW11423@atdesk.com

You can build as complicated a mixin graph as you can a MI graph. The
difference is that because mixins are modules, they don’t have their
own state, but instead parasitically use the state of the class into
which they are mixed.

U sure about that? Try this:

p X.new.instance_variables

I think you misunderstood what Dave was saying.

I don’t think so; maybe I wasn’t clear enough. The error is in the sentence
“The difference is that because mixins are modules, they don’t have their
own state, but instead parasitically use the state of the class into which
they are mixed.”

First, when talking about “their own state” this refers strictly speaking to
the class and module instance themself. But I think, this is not what Dave
wanted to say. Dave wanted to talk about the state of instances that are
not classes or modules.

Now the scene becomes clearer: modules don’t use the state of the class,
they even don’t use the state that a class defined (“defined” as in C++
and Java, where the class defines instance variables). That’s because
neither classes nor modules define the state of an instance. Instance
variables come into existence by executing code (i.e. methods), and they are
bound to the instance to which the method belongs. It doesn’t matter which
class or module defined the method. Important is the runtime instance at
hand.

So Ruby avoids the typical MI problems simply by not letting classes define
instance variables. There’s no space allocation for instance variables
because of a class definition. There’s just a bunch o methods that are
executed sooner or later. “initialize” is not special with respect to
instance variables: it’s just automatically executed on instance creation.
Neither classes nor modules define their own scope at the moment (that would
only change with @_var).

Classes and modules in Ruby have very little differences. The main
difference beeing that there is only single inheritance between classes
while there is multiple inheritance with modules. Additionally the syntax
to define these inheritance relationships is different.

This prints [ “@foo”, “@bar” ].

Right.

That’s because the module and the class in which it is
included share the same state, exactly as Dave pointed out.

Hopefully I have made clearer what I was up to…

Kind regards

robert
···

On Thu, Dec 04, 2003 at 02:37:06AM +0900, Robert Klemme wrote:

I’m going to speak about inheritance of implementation here; inheritance
of interface is a separate issue that doesn’t really apply to Ruby.

With multiple inheritance, every class knows exactly what its immediate
ancestors are and can explicitly call functions in those classes.
However, complex hierarchies that depend on subtleties of relationships
between base class and derived class are generally brittle and hard to
follow.

With Ruby’s mixins, because inheritance is always single-inheritance,
Ruby may adjust the order of inheritance so that a class or module
doesn’t necessarily know what its immediate ancestors are. This is less
flexible, but it’s conceptually much simpler and easier to implement
than MI.

I’m yet to see an example using inheritance of implementation where
multiple inheritance would work but Ruby mixins would not that didn’t
make me cringe.

Paul

···

On Thu, Dec 04, 2003 at 03:09:52AM +0900, T. Onoma wrote:

What you say is true enough. But I am wondering what it is that supposedly
Mutiple-in gives you that Mix-in does not, which was implied by matz, albiet
that the it is better Ruby’s way.

I am moving my ruby program file from my winbox to my linux( redhat 9 ) box.
I’ve got ruby 1.8.1 installed on my linux box. However when I run my script
the following lines error out:

smtp = Net::SMTP::new( server )
smtp.start( domain , username , password , “cram_md5” )

It complains about:

/usr/local/lib/ruby/1.8/net/protocol.rb:83:in ‘initialize’: getaddrinfo:
Name or service not known( SocketError )
from /usr/local/lib/ruby/1.8/net/protocol.rb:83:in 'new’
from /usr/local/lib/ruby/1.8/net/protocol.rb:83:in 'connect’
from /usr/local/lib/ruby/1.8/net/protocol.rb:82:in 'timeout’
etc…etc…etc…

It works beautifully on my Windows box. Any ideas?

Zach