Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

What's so special about operators, built-in classes and modules?

5 views
Skip to first unread message

Jim Freeze

unread,
Jul 25, 2005, 6:43:29 PM7/25/05
to
I just noticed this little quirk. Is there something
I am doing wrong?

module Mod
def *(other)
puts "#{self} * #{other}"
end
end

class String
include Mod
end

"ff" * 5 #=> nothing

But, if I add the method explicitly instead of through a module I get:

class String
#include Mod
def *(other)
puts "#{self} * #{other}"
end
end

"ff" * 5 #=> "ff" * 5

This seems to be a quirk (bug?) and only happens when mixing modules,
built in classes (like Array) and operator methods.

Mixing in a module works fine with the combinations:
Non built-in class, operators
Built-in class, non operator method

--
Jim Freeze


Florian Frank

unread,
Jul 25, 2005, 7:26:21 PM7/25/05
to
On 2005-07-26 07:43:29 +0900, Jim Freeze wrote:
[...]

module Mod
def f; :f;end
end

class A;
end
class A;
include Mod
end
A.new.f # => :f

class B
def f; :g;end
end
class B
include Mod
end
B.new.f # => :g

class B
def f; :f;end
end
B.new.f # => :f

String.method_defined?(:*) # => true

--
Florian Frank


Jim Freeze

unread,
Jul 26, 2005, 8:48:34 AM7/26/05
to
* Florian Frank <fl...@nixe.ping.de> [2005-07-26 08:26:21 +0900]:

> class B
> def f; :g;end
> end
> class B
> include Mod
> end
> B.new.f # => :g

Thanks Forian. For some reason I always thought that including a mod
would shadow old methods.
I suppose for my method to work (no pun intended), the standard
operating procedure is to:

class B
alias :_orig_f
remove_method :f
include Mod
end

I'm a little slow in getting around to these types of things, I'm
surprised I haven't seen an RCR to reduce this to a single line.

--
Jim Freeze


Florian Frank

unread,
Jul 26, 2005, 9:28:40 AM7/26/05
to
On 2005-07-26 21:48:34 +0900, Jim Freeze wrote:
> I'm a little slow in getting around to these types of things, I'm
> surprised I haven't seen an RCR to reduce this to a single line.

You can use Ruby to do most of the work:

module Mod
def f; :"new-f"; end
def self.included(o)
instance_methods(false).each do |m|
o.instance_eval do
alias_method("_orig_#{m}", m)
remove_method(m)
end
end
super
end
end

class A


def f; :f; end
end

A.new.f # => :f

class A
include Mod
end

A.new._orig_f # => :f
A.new.f # => :"new-f"

--
Florian Frank


Joel VanderWerf

unread,
Jul 26, 2005, 3:52:29 PM7/26/05
to

Including a module is just like inheriting from a class--the module is
above you in the ancestor list. I guess the intuitive meaning of
"include" might be different--one might think it meant "define all
methods from the module at this point in my class definition". Maybe
"inherit <module>" would be a better name for the construct...

So would the RCR be for a construct that inserted a module between each
instance of B and B itself?


Jim Freeze

unread,
Jul 26, 2005, 4:28:14 PM7/26/05
to
* Joel VanderWerf <vj...@path.berkeley.edu> [2005-07-27 04:52:29 +0900]:

> > Thanks Forian. For some reason I always thought that including a mod
> > would shadow old methods.
> > I suppose for my method to work (no pun intended), the standard
> > operating procedure is to:
> >
> > class B
> > alias :_orig_f
> > remove_method :f
> > include Mod
> > end
> >

> Including a module is just like inheriting from a class--the module is
> above you in the ancestor list. I guess the intuitive meaning of
> "include" might be different--one might think it meant "define all
> methods from the module at this point in my class definition". Maybe
> "inherit <module>" would be a better name for the construct...

My simple thought process was always thinking that 'include'ing a Module
was the same as writing the methods myself. So

class A
def m
puts "A#m"
end
def m
puts :m
end
end
A.new.m #=> :m

was the same thing as

module Mod
def m
puts :m
end
end
class A
def m
puts "A#m"
end
include Mod
end
A.new.m #=> :m

So, I thought it was redefining the method and the old method
was being lost if it did not have an alias.

But, as you say, it is more like inheritance.

> So would the RCR be for a construct that inserted a module between each
> instance of B and B itself?

Would be nice if the notation was external to the class
since there is no difference between:

class A
include Mod
def m; puts "A#m"; end
end

and

class A
def m; puts "A#m"; end
include Mod
end
--
Jim Freeze


Daniel Brockman

unread,
Jul 26, 2005, 9:48:36 PM7/26/05
to
One week and five days ago,

Joe Van Dyk <joev...@gmail.com> writes:

> I thought that the methods and constants in a module were
> just inserted into a class.

Daniel Brockman <dan...@brockman.se> writes:

> Yet another reason why modules and classes should
> be unified.

Austin Ziegler <halos...@gmail.com> writes:

> I don't see it, personally. I really don't see why they
> should be unified in the least.

Twelve hours ago,

Jim Freeze <j...@freeze.org> writes:

> For some reason I always thought that including a mod
> would shadow old methods.

Dear Austin,

While the superficial and cosmetic difference between these
two almost completely equivalent concepts continue to
mislead users, do you still not see “in the least” any
reason whatsoever to unify them?

Oh, and before someone comes shouting “but classes can be
instantiated and modules can't,” let me just post this:

class Module
def new(*a, &b)
const_defined?(:Viagra) or
const_set(:Viagra, Class.new.include(self))
const_get(:Viagra).new(*a, &b)
end
end

--
Daniel Brockman <dan...@brockman.se>

So really, we all have to ask ourselves:
Am I waiting for RMS to do this? --TTN.

Austin Ziegler

unread,
Jul 27, 2005, 8:20:54 AM7/27/05
to
On 7/26/05, Daniel Brockman <dan...@brockman.se> wrote:
> Joe Van Dyk <joev...@gmail.com> writes:
> > I thought that the methods and constants in a module were
> > just inserted into a class.
>
> Daniel Brockman <dan...@brockman.se> writes:
> > Yet another reason why modules and classes should
> > be unified.
>
> Austin Ziegler <halos...@gmail.com> writes:
> > I don't see it, personally. I really don't see why they
> > should be unified in the least.
>
> Twelve hours ago,
> Jim Freeze <j...@freeze.org> writes:
> > For some reason I always thought that including a mod
> > would shadow old methods.
>
> Dear Austin,
>
> While the superficial and cosmetic difference between these
> two almost completely equivalent concepts continue to
> mislead users, do you still not see "in the least" any
> reason whatsoever to unify them?

Nope. I'll note that others have argued better in favour of this than
you have and they're still not unified. I think that unification would
increase the confusion far MORE than what is currently present.

> Oh, and before someone comes shouting "but classes can be
> instantiated and modules can't," let me just post this:
>
> class Module
> def new(*a, &b)
> const_defined?(:Viagra) or
> const_set(:Viagra, Class.new.include(self))
> const_get(:Viagra).new(*a, &b)
> end
> end

That's not instantiating a module. It's cute, but it's not
instantiating a module.

-austin
--
Austin Ziegler * halos...@gmail.com
* Alternate: aus...@halostatue.ca


Daniel Brockman

unread,
Jul 27, 2005, 11:34:46 AM7/27/05
to
Austin Ziegler <halos...@gmail.com> writes:

>> While the superficial and cosmetic difference between
>> these two almost completely equivalent concepts continue
>> to mislead users, do you still not see "in the least" any
>> reason whatsoever to unify them?
>
> Nope.

Then I'm forced to conclude that you are shying away from
the truth, as it is staring you in the face.

> I'll note that others have argued better in favour
> of this than you have and they're still not unified.

That's a new one — argument by pointing out that there are
better arguments in favor of the opposing side.

> I think that unification would increase the confusion far
> MORE than what is currently present.

That is a reasonable belief. Indeed, I'm not completely
sure myself that unification would reduce net confusion.
So I'd be interested in seeing some arguments.

Here is an example of an argument:

Whenever you bring up the issue of modules vs. classes,
there will generally be at least one person who believes
that including a module is the same as copying its body.
This confusion would go away if the two were unified.

>> class Module
>> def new(*a, &b)
>> const_defined?(:Viagra) or
>> const_set(:Viagra, Class.new.include(self))
>> const_get(:Viagra).new(*a, &b)
>> end
>> end
>
> That's not instantiating a module. It's cute, but it's not
> instantiating a module.

Of course it's not instantiating a module, but it's pretty
much _as good as_ instantiating a module. It lets you use
modules instead of classes, which demonstrates that the
distinction is superficial.

Ara.T.Howard

unread,
Jul 27, 2005, 12:07:09 PM7/27/05
to
On Thu, 28 Jul 2005, Daniel Brockman wrote:

> That is a reasonable belief. Indeed, I'm not completely sure myself that
> unification would reduce net confusion. So I'd be interested in seeing some
> arguments.

well - classes can't do this

module MainHelper
...
end

module SetupMain
include MainHelper
def run
...
end
end

module QueryMain
include MainHelper
def run
...
end
end

module BackupMain
include MainHelper
def run
...
end
end

class Main
def main
table = {
SETUP => SetupMain,
QUERY => QueryMain,
BACKUP => BackupMain,
}
modul = table[ mode ]
extend modul
run
end
end

this sort of aggregation can be very nice for source management when classes
are growing large - one can simply make the class be what it needs to be and
nothing more. in short - classes do not support ad hoc aggreation, which is
very nice feature to give up.

>
> Here is an example of an argument:
>
> Whenever you bring up the issue of modules vs. classes,
> there will generally be at least one person who believes
> that including a module is the same as copying its body.
> This confusion would go away if the two were unified.

this is a similar 'argument':

in c most people think that a definition like

int foobar (const char * string);

will prevent people from modifiying string. it won't. for that one needs

int foobar (const char * const string);

why not unify them?

the answer is obvious: because they are differnet. a focus on clarifying
doccumentation might be wiser in this case. and, in the end, certain people
are simply going to have to be told to rtfm - not everything can be intuitive
AND powerful.

>> That's not instantiating a module. It's cute, but it's not
>> instantiating a module.
>
> Of course it's not instantiating a module, but it's pretty
> much _as good as_ instantiating a module. It lets you use
> modules instead of classes, which demonstrates that the
> distinction is superficial.

does it?

harp:~ > cat a.rb


class Module
def new(*a, &b)

(@__klass__ ||= (m = self and Class::new{ include m }))::new(*a, &b)
end
end

module M
class << self
def class_method
42
end
end
def instance_method
42
end
end

m = M::new
p m.instance_method
p m.class.class_method

harp:~ > ruby a.rb
42
a.rb:21: undefined method `class_method' for #<Class:0xb75d0480> (NoMethodError)

and, of course, you still can't inherit from M - but i realize this needed be
so.

i think i'm with austin on this one.

cheers.

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| My religion is very simple. My religion is kindness.
| --Tenzin Gyatso
===============================================================================

Daniel Brockman

unread,
Jul 27, 2005, 12:42:39 PM7/27/05
to
"Ara.T.Howard" <Ara.T....@noaa.gov> writes:

>> That is a reasonable belief. Indeed, I'm not completely
>> sure myself that unification would reduce net confusion.
>> So I'd be interested in seeing some arguments.
>

> well - classes can't [extend objects] [...]

Is that an argument in favor of unifying them?

>> Here is an example of an argument:
>>
>> Whenever you bring up the issue of modules vs. classes,
>> there will generally be at least one person who believes
>> that including a module is the same as copying its body.
>> This confusion would go away if the two were unified.
>
> this is a similar 'argument':
>
> in c most people think that a definition like
>
> int foobar (const char * string);
>
> will prevent people from modifiying string. it won't.
> for that one needs
>
> int foobar (const char * const string);
>
> why not unify them?
>
> the answer is obvious: because they are differnet.

I agree. My point is that Ruby's classes and modules are
very much alike. If ‘const char *’ and ‘const char * const’
were very much alike, I'd be in favor of unifying them.
But since the two pointer types are not alike at all, your
analogy doesn't apply.

I'm talking about two very similar concepts that are
commonly mistaken for very different concepts, while you are
talking about two very different concepts that are commonly
mistaken for equal concepts. Do you see the difference?

> a focus on clarifying doccumentation might be wiser in
> this case.

Documentation in always nice, but I'm afraid the quality of
the documentation is irrelevant to the discussion at hand.

> and, in the end, certain people are simply going to have
> to be told to rtfm

Granted.

> not everything can be intuitive AND powerful.

But realize that what I'm saying is that Ruby is *not* more
powerful with classes and modules separate than it would be
with them unified. I'm saying that Ruby would be equally
powerful (nay, more powerful) after the unification.

Would it be more intuitive? I think so.

Daniel Brockman

unread,
Jul 27, 2005, 12:49:02 PM7/27/05
to
Hmm, for some reason this part of your message was left out
of my reply buffer, so I forgot to reply to it!

"Ara.T.Howard" <Ara.T....@noaa.gov> writes:

>>> That's not instantiating a module. It's cute, but it's
>>> not instantiating a module.
>>
>> Of course it's not instantiating a module, but it's
>> pretty much _as good as_ instantiating a module. It lets
>> you use modules instead of classes, which demonstrates
>> that the distinction is superficial.
>
> does it?
>

> [Complicated way of saying module.new.class != module.]

As I trust you are already aware, that's easily fixed:
Just redefine the ‘class’ method to return the module.

> and, of course, you still can't inherit from M - but i
> realize this needed be so.

Yes, you can:

module N
include M
end

Ara.T.Howard

unread,
Jul 27, 2005, 1:11:09 PM7/27/05
to
This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

twi...@comcast.net

unread,
Jul 27, 2005, 1:12:58 PM7/27/05
to
>Whenever you bring up the issue of modules vs. classes,
>there will generally be at least one person who believes
>that including a module is the same as copying its body.
>This confusion would go away if the two were unified.

It'd also go away if the rdoc were better:
-------------------------------------------- Module#append_features
append_features(mod) => mod
-------------------------------------------------------------------
When this module is included in another, Ruby calls
+append_features+ in this module, passing it the receiving module
in _mod_. Ruby's default implementation is to add the constants,
methods, and module variables of this module to _mod_ if this
module has not already been added to _mod_ or one of its ancestors.
See also +Module#include+.

says nothing about "if method is already defined."

>well - classes can't do this
><snip>multiple inheritance</snip>
Why can't classes do that? Is there anything about the nature of classes such that, should we decide to make a change to the Ruby language, it would cause problems if one could "include" classes?

My answer (and I could be wrong) is this: I think the class/module separation is an artificial separation made *intentionally*, to make multiple inheritance hard. Classes and Modules inspire different frames of mind:
* Classes are these self-contained things that need only their constructor called, and are then good to go.
* Modules have no constructor, and are merely a collection of methods, that may or may not be dependent on being included in classes.

I agree that this gap could easily be bridged, such that the Cladule could a)be instantiated, and b)be included, but I believe that it's an artificial limitation in place to limit this sort of confusion:

class SomeDependentComponent
def initialize(name); @name = name end
def do_something
log "component #@name is doing something"
#...
end
end

class SomeMainComponent
include SomeDependentComponent
def initialize(name); @name = name end
def run; do_something end
end

Now, do I think that such an artificial limitation is a good idea? I dunno. Certainly, artificial limitations aren't always good ideas, to me. I like Ruby more than Java, for instance.

Would I prefer not to have this artificial limitation? I think yes. I don't think I'd ever make use of the additional freedom, but I'd be happy with the one less concept to think about.

Devin


ts

unread,
Jul 27, 2005, 1:18:16 PM7/27/05
to
>>>>> "t" == twifkak <twi...@comcast.net> writes:

t> My answer (and I could be wrong) is this: I think the class/module
t> separation is an artificial separation made *intentionally*, to make
^^^^^^^
t> multiple inheritance hard.
^^^^^^^^^^^^^^^^^^^^^^^^^
Just to don't have multi-inheritance.


Guy Decoux

Ara.T.Howard

unread,
Jul 27, 2005, 1:21:57 PM7/27/05
to
On Thu, 28 Jul 2005, Daniel Brockman wrote:

> "Ara.T.Howard" <Ara.T....@noaa.gov> writes:
>
>>> That is a reasonable belief. Indeed, I'm not completely
>>> sure myself that unification would reduce net confusion.
>>> So I'd be interested in seeing some arguments.
>>
>> well - classes can't [extend objects] [...]
>
> Is that an argument in favor of unifying them?

i don't think so. the reason is that if classes could extend objects we'd
have a real issue with ancestors/inheritence. what i mean is that if one
could

class A
end
class B
include A
end

and this were the 'same' as

class B < A
end

then that __would__ be confusing since including multiple classes would imply
multiple inheritence. if it did not imply multiple inheritence would the only
difference be that one (B < A) made b.is_a?(A) true while the other (B.include
A) did not - even though, for all intents and purposes they could do all the
same things. this seems broken and confusing either way - tough i'll admit
the idea is interesting...

> I agree. My point is that Ruby's classes and modules are
> very much alike.

execept - and this is important - wrt inheritence.

> were very much alike, I'd be in favor of unifying them.
> But since the two pointer types are not alike at all, your
> analogy doesn't apply.

and i'm saying they are not that much alike because on this crucial
difference.

> Documentation in always nice, but I'm afraid the quality of
> the documentation is irrelevant to the discussion at hand.

requiring people to understand the language fully, regardless of what that
takes, before attempting to change it is never really irrelevant is it?

>> and, in the end, certain people are simply going to have
>> to be told to rtfm
>
> Granted.
>
>> not everything can be intuitive AND powerful.
>
> But realize that what I'm saying is that Ruby is *not* more
> powerful with classes and modules separate than it would be
> with them unified. I'm saying that Ruby would be equally
> powerful (nay, more powerful) after the unification.

well - if you can work out how inheritence would work out - then maybe.
realize that i'm one of those people that think that normal hackers cannot
handle multiple inheritence anyhow and that, at the very least, it's an idea
far less powerfull than mixins.

Daniel Brockman

unread,
Jul 27, 2005, 1:38:21 PM7/27/05
to
"Ara.T.Howard" <Ara.T....@noaa.gov> writes:

>>> and, of course, you still can't inherit from M - but i
>>> realize this needed be so.
>>
>> Yes, you can:
>>
>> module N
>> include M
>> end
>

> the problem is a bit deeper than that and stem from the
> fact that including a module does not inject the included
> modules singleton methods into the 'includee'.

Right, but to me that is just another reason to unify.
How is this inconsistency a feature? Why is it not fixed?

Does any code depend on the fact that including a module
does not pull in its singleton methods?

(This deserves a thread of its own, and in fact probably
already has at least one. I'll search the archives later.)

> [snipped nice example code]

> i'm not saying it's not possible - just that it's a bit
> more work than you're suggesting. doing things
> consistently at an object, class, module, and
> singleton_class level gets very confusing very quicky -
> just check out the code for my traits lib to see just how.
> ;-)
>
> i personally often get around this detail by
>
> module M
> module ClassMethods
> end
> module InstanceMethods
> end
> include InstanceMethods
> self.extend ClassMethods
> def self::included other
> class << other
> include InstanceMethods
> end
> other.extend ClassMethods
> end
> end
>
> or something similar - in otherwords factor out class
> methods so that can be added individually to other
> classes/modules when they are included there. thus begins
> the trickiness...

Yes, I use similar hacks too. But don't you agree that it
would be nicer if modules and classes were consistent in
this regard, rendering these hacks unnecessary?

(I realize that I'm shifting the discussion instead of
meeting your arguments.)

> (ps. for some reason the charset from your message is very
> odd - it may be on my end but thought you might like to
> know. it looks like some sort of escape chars around '@'
> signs - coloring?)

Hmm... sounds weird. I do tend to use Unicode characters,
specifically quotation marks. How does this look?

‘foo’ “bar”

It's supposed to be the word foo in single quotes followed
by the word bar in double quotes.

Yukihiro Matsumoto

unread,
Jul 27, 2005, 1:44:51 PM7/27/05
to
Hi,

In message "Re: What's so special about operators, built-in classes and modules?"


on Thu, 28 Jul 2005 01:42:39 +0900, Daniel Brockman <dan...@brockman.se> writes:

|> well - classes can't [extend objects] [...]
|
|Is that an argument in favor of unifying them?

Then you will have complex network of classes instead of simple tree
structure, sharing code with modules. That makes things much complex,
without buying you anything except for the feeling of being more generic.

matz.


twi...@comcast.net

unread,
Jul 27, 2005, 1:51:42 PM7/27/05
to
>Then you will have complex network of classes instead of simple tree
>structure, sharing code with modules.
How does a complex network of classes differ from a complex network of mixins? The main difference that I see is, as Ara pointed out, #is_a?. But I could be missing something. I usually am.

>Hmm... sounds weird. I do tend to use Unicode characters,
>specifically quotation marks. How does this look?

http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/149716

Devin


Daniel Brockman

unread,
Jul 27, 2005, 1:54:10 PM7/27/05
to
"Ara.T.Howard" <Ara.T....@noaa.gov> writes:

> On Thu, 28 Jul 2005, Daniel Brockman wrote:
>
>> "Ara.T.Howard" <Ara.T....@noaa.gov> writes:
>>
>>>> That is a reasonable belief. Indeed, I'm not completely
>>>> sure myself that unification would reduce net confusion.
>>>> So I'd be interested in seeing some arguments.
>>>
>>> well - classes can't [extend objects] [...]
>>
>> Is that an argument in favor of unifying them?
>
> i don't think so. the reason is that if classes could
> extend objects we'd have a real issue with
> ancestors/inheritence. what i mean is that if one could
>
> class A
> end
> class B
> include A
> end
>
> and this were the 'same' as
>
> class B < A
> end
>
> then that __would__ be confusing since including multiple
> classes would imply multiple inheritence.

And how is that confusing? It's exactly what currently
happens when you include multiple modules.

module A ; end
module B ; end

class C
include A
include B
end

C.new.is_a? A #=> true
C.new.is_a? B #=> true

> if it did not imply multiple inheritence would the only
> difference be that one (B < A) made b.is_a?(A) true while
> the other (B.include A) did not -

I don't see how this could ever make sense.

> even though, for all intents and purposes they could do
> all the same things. this seems broken and confusing
> either way - tough i'll admit the idea is interesting...

The version that doesn't have B.include(A) imply b.is_a?(A)
does seem broken and confusing, but is a straw man.

>> I agree. My point is that Ruby's classes and modules are
>> very much alike.
>
> execept - and this is important - wrt inheritence.

How so?

>> were very much alike, I'd be in favor of unifying them.
>> But since the two pointer types are not alike at all,
>> your analogy doesn't apply.
>
> and i'm saying they are not that much alike because on
> this crucial difference.

See above.

>> Documentation in always nice, but I'm afraid the quality
>> of the documentation is irrelevant to the discussion
>> at hand.
>
> requiring people to understand the language fully,
> regardless of what that takes, before attempting to change
> it is never really irrelevant is it?

If anything I said in this thread was out of ignorance, I
apologize for my arrogance. However, I would appreciate it
if you would point any such errors out.

>>> not everything can be intuitive AND powerful.
>>
>> But realize that what I'm saying is that Ruby is *not*
>> more powerful with classes and modules separate than it
>> would be with them unified. I'm saying that Ruby would
>> be equally powerful (nay, more powerful) after
>> the unification.
>
> well - if you can work out how inheritence would work out
> - then maybe.

But inheritance would work exactly the same as it does now.

> realize that i'm one of those people that think that
> normal hackers cannot handle multiple inheritence anyhow
> and that, at the very least, it's an idea far less
> powerfull than mixins.

How is multiple inheritance far less powerful than mixins?

(I actually consider Ruby's mixins to *be* a kind of
multiple inheritance, but I'll play along for a while.)

Joel VanderWerf

unread,
Jul 27, 2005, 1:57:33 PM7/27/05
to
Very nice technique, but...

Ara.T.Howard wrote:
> module M
> module ClassMethods
> end
> module InstanceMethods
> end
> include InstanceMethods
> self.extend ClassMethods
> def self::included other
> class << other
> include InstanceMethods

^^^^^^^^^^^^^^^^^^^^^^^
This is redundant.


> end
> other.extend ClassMethods
> end
> end

For the newbies: In the old, old days (1.6 maybe), we had to use
#append_features instead of #included, and that did require explicitly
including the module. And sometimes we had to whack it with a dinosaur
bone to make it work.

Btw, the doc for append_features is unclear (as someone else on this
thread pointed out) about the difference between including a module and
adding methods:

------------------------------------------------- Module#append_features
append_features(mod) => mod
------------------------------------------------------------------------

Sylvain Joyeux

unread,
Jul 27, 2005, 2:02:48 PM7/27/05
to
> (I actually consider Ruby's mixins to *be* a kind of
> multiple inheritance, but I'll play along for a while.)
Theoretically, you can't have a base class use derived class methods
because a) the base class should be instantiable b) in OO you can't force
the derived class to define a method.

Dynamic language allow (b) but it would feel strange anyway

About (a), one assumption you have is that modules should be instantiable.
Enumerable, for instance, is not even using the trick you sent earlier
because no method in the resulting object would be usable.

In the C++ world (if you know it), modules are a form of CRTP.
Regards,
--
Sylvain Joyeux


Ara.T.Howard

unread,
Jul 27, 2005, 2:15:14 PM7/27/05
to

gabriele renzi

unread,
Jul 27, 2005, 3:20:19 PM7/27/05
to
twi...@comcast.net ha scritto:

>>Then you will have complex network of classes instead of simple tree
>>structure, sharing code with modules.
>
> How does a complex network of classes differ from a complex network of mixins? The main difference that I see is, as Ara pointed out, #is_a?. But I could be missing something. I usually am.

you don't have a network of mixins, just a tree

Nikolai Weibull

unread,
Jul 27, 2005, 3:37:10 PM7/27/05
to
Ara.T.Howard wrote:

^--- Why are you doing this?

> On Thu, 28 Jul 2005, Daniel Brockman wrote:

> > "Ara.T.Howard" <Ara.T....@noaa.gov> writes:

> > > (ps. for some reason the charset from your message is very odd -
> > > it may be on my end but thought you might like to know. it looks
> > > like some sort of escape chars around '@' signs - coloring?)

> > Hmm... sounds weird. I do tend to use Unicode characters,
> > specifically quotation marks. How does this look?
> >
> > ‘foo’ “bar”

Works fine on my end. Thank you for making my reading experience that
much more pleasurable.

> like this
>
> .[0m~@~Xfoo.[0m~0~X .[0m~@~\bar.[0m~@~]

Looks more like a Lisp (format) string than ANSI coloring escapes, but
the [0m is certainly suspicious ;-),
nikolai

--
Nikolai Weibull: now available free of charge at http://bitwi.se/!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}


Pit Capitain

unread,
Jul 27, 2005, 3:47:02 PM7/27/05
to
twi...@comcast.net schrieb:

>> Then you will have complex network of classes instead of simple
>> tree structure, sharing code with modules.
>
> How does a complex network of classes differ from a complex network
> of mixins? The main difference that I see is, as Ara pointed out,
> #is_a?. But I could be missing something. I usually am.

For me, the main difference between modules and classes is that classes
"define" state (instance variables), not only behaviour (methods). One
classic problem with multiple inheritence is the so called diamond:

class A
def initialize(val)
@var = val
end
end

class B
include A
def initialize
super(5)
end
end

class C
include A
def initialize
super(42)
end
end

class D
include B
include C
end

d = D.new

Now, how many instances of A are in d? Two (one for B, one for C) or
one? If one, what is the value of @var? You avoid such problems with
mixins (modules).

Regards,
Pit


Ara.T.Howard

unread,
Jul 27, 2005, 4:05:01 PM7/27/05
to
On Thu, 28 Jul 2005, Daniel Brockman wrote:

> And how is that confusing? It's exactly what currently
> happens when you include multiple modules.
>
> module A ; end
> module B ; end
>
> class C
> include A
> include B
> end
>
> C.new.is_a? A #=> true
> C.new.is_a? B #=> true
>
>> if it did not imply multiple inheritence would the only
>> difference be that one (B < A) made b.is_a?(A) true while
>> the other (B.include A) did not -
>
> I don't see how this could ever make sense.
>
>> even though, for all intents and purposes they could do
>> all the same things. this seems broken and confusing
>> either way - tough i'll admit the idea is interesting...
>
> The version that doesn't have B.include(A) imply b.is_a?(A)
> does seem broken and confusing, but is a straw man.

straw man! i'm not that smart ;-)

i was doing too much at once. all i was trying to say was that

B < A

means inheritence. if you also want to be able to

class B
include A
include Z
end

and have that also mean inheritecne - then multiple inheritence must be
addressed. my point is simply that i don't think you can unify modules and
classes without also intrducing multiple inheritence - which is what matz's
comment about complex graphs was getting at... (i think)

>>> I agree. My point is that Ruby's classes and modules are
>>> very much alike.
>>
>> execept - and this is important - wrt inheritence.
>
> How so?

you can't currently do this

http://en.wikipedia.org/wiki/Diamond_problem

with mixins. if unification took place you could.

>> requiring people to understand the language fully,
>> regardless of what that takes, before attempting to change
>> it is never really irrelevant is it?
>
> If anything I said in this thread was out of ignorance, I
> apologize for my arrogance. However, I would appreciate it
> if you would point any such errors out.

i didn't mean you - but people learning ruby. improved docs could benefit
them. sorry for confusion.

>>> more powerful with classes and modules separate than it
>>> would be with them unified. I'm saying that Ruby would
>>> be equally powerful (nay, more powerful) after
>>> the unification.
>>
>> well - if you can work out how inheritence would work out
>> - then maybe.
>
> But inheritance would work exactly the same as it does now.
>
>> realize that i'm one of those people that think that
>> normal hackers cannot handle multiple inheritence anyhow
>> and that, at the very least, it's an idea far less
>> powerfull than mixins.
>
> How is multiple inheritance far less powerful than mixins?

because people don't use it well - it's complexity precludes average
programers using it in the very situations where it could be most benefit..
just at it's prevelance in languages which support i and compare that to the
useage of mixins in ruby, for example.

mixins are powerful because they provide 90% of the functionality of mi with
10% of the debugging. this is primarily because it's easy to affect the
method search tree.

interesting:

http://64.233.167.104/search?q=cache:cSj6WP7jx2wJ:csl.ensm-douai.fr/research/uploads/nouryBouraqadi.esug2003ResearchTrack.pdf+mixin+vs+multiple+inheritence&hl=en

twi...@comcast.net

unread,
Jul 27, 2005, 4:34:22 PM7/27/05
to
>Now, how many instances of A are in d? Two (one for B, one for C) or
>one? If one, what is the value of @var? You avoid such problems with
>mixins (modules).

In your example (and my imaginary Ruby 2.1), @var is not defined. D descends directly from Object, not A, B, or C. As such, D.new calls D#initialize, which is defined on Object as a method with no parameters. A#initialize, B#initialize, and C#initialize never get included in the D class, as D's superclass, Object, already defines it.

Gimme another! This is fun.

Devin
*sigh* Years spent in school and at work playing the human computer... I actually find it _fun_ now...

----


twi...@comcast.net schrieb:
>> Then you will have complex network of classes instead of simple
>> tree structure, sharing code with modules.
>
> How does a complex network of classes differ from a complex network
> of mixins? The main difference that I see is, as Ara pointed out,
> #is_a?. But I could be missing something. I usually am.

For me, the main difference between modules and classes is that classes
"define" state (instance variables), not only behaviour (methods). One
classic problem with multiple inheritence is the so called diamond:

class A
def initialize(val)
@var = val
end
end

class B
include A
def initialize
super(5)
end

end

class C
include A

Joel VanderWerf

unread,
Jul 27, 2005, 5:13:52 PM7/27/05
to
Pit Capitain wrote:
> twi...@comcast.net schrieb:
>
>>> Then you will have complex network of classes instead of simple
>>> tree structure, sharing code with modules.
>>
>>
>> How does a complex network of classes differ from a complex network
>> of mixins? The main difference that I see is, as Ara pointed out,
>> #is_a?. But I could be missing something. I usually am.
>
>
> For me, the main difference between modules and classes is that classes
> "define" state (instance variables), not only behaviour (methods). One
> classic problem with multiple inheritence is the so called diamond:

Actually, wouldn't it make more sense to say that neither classes nor
modules define state, but rather that methods do?

classirb(main):001:0> class A; attr_accessor :x; end
=> nil
irb(main):002:0> a = A.new
=> #<A:0xb7d85bb0>
irb(main):003:0> a.x = 6
=> 6
irb(main):004:0> a
=> #<A:0xb7d85bb0 @x=6>
^^^^
irb(main):005:0> module M; attr_accessor :y; end
=> nil
irb(main):006:0> class A; include M; end
=> A
irb(main):007:0> a
=> #<A:0xb7d85bb0 @x=6>
irb(main):008:0> a.y = 8
=> 8
irb(main):009:0> a
=> #<A:0xb7d85bb0 @y=8, @x=6>
^^^^


Daniel Brockman

unread,
Jul 27, 2005, 8:34:44 PM7/27/05
to
"Ara.T.Howard" <Ara.T....@noaa.gov> writes:

>>> the problem is a bit deeper than that and stem from the
>>> fact that including a module does not inject the
>>> included modules singleton methods into the 'includee'.
>>
>> Right, but to me that is just another reason to unify.
>> How is this inconsistency a feature? Why is it not fixed?
>>
>> Does any code depend on the fact that including a module
>> does not pull in its singleton methods?
>

> i'd say __all__ code depends on that. otherwise
>
> module M
> def self::new
> raise
> end
> end
> class C
> include M
> end
>
> c = C::new

Surely you are not suggesting that all code defines
singleton ‘new’ methods on modules?

Considering that this doesn't work,

class X
def self.new
raise
end
end

class Y < X
end

x = X.new

why do you expect your example to work?

I don't get why Y's singleton class inherits from X's,
while C's *doesn't* inherit from M's.

> i'd imagine this is the (one of) reason(s) for the
> current behaviour.

Why are you defining M.new? Do you have actual code that
does this?

>> Yes, I use similar hacks too. But don't you agree that it
>> would be nicer if modules and classes were consistent in
>> this regard, rendering these hacks unnecessary?
>

> yes - i just am not seeing how it could be done in a way
> that preserved or added to current functionality and was
> simpler.

No, it would not be possible to retain full backwards
compatibility, but I cannot think of a real-world case in
which actual problems would result.

> inheritence needs to be addressed specifically for it to
> make sense.

Why do you say that?

>> How does this look?
>>
>> ‘foo’ “bar”
>

> like this
>
> .[0m~@~Xfoo.[0m~0~X .[0m~@~\bar.[0m~@~]

Out of curiosity, what mail reader do you use?

--
Daniel Brockman <dan...@brockman.se>

Daniel Brockman

unread,
Jul 27, 2005, 8:42:54 PM7/27/05
to
gabriele renzi <surren...@remove-yahoo.it> writes:

> you don't have a network of mixins, just a tree

This is just plain wrong. Mixin inheritance networks can
come in the shape of any directed acyclic graph.

--
Daniel Brockman <dan...@brockman.se>

Daniel Brockman

unread,
Jul 27, 2005, 8:52:04 PM7/27/05
to
Pit Capitain <p...@capitain.de> writes:

> For me, the main difference between modules and classes is
> that classes "define" state (instance variables), not only
> behaviour (methods).

Yet there are many examples of modules whose modules set
instance variables, and there are many examples of classes
whose methods do not.

That alleged difference is not grounded in reality.

> One classic problem with multiple inheritence is the so
> called diamond:
>
> class A
> def initialize(val)
> @var = val
> end
> end
>
> class B
> include A
> def initialize
> super(5)
> end
> end
>
> class C
> include A
> def initialize
> super(42)
> end
> end
>
> class D
> include B
> include C
> end
>
> d = D.new

As has been pointed out countless times already, the diamond
inheritance problem already exists in Ruby:

module A


def initialize(val)
@var = val
end
end

module B


include A
def initialize
super(5)
end
end

module C


include A
def initialize
super(42)
end
end

class D
include B
include C
end

> Now, how many instances of A are in d?

One (assuming you mean how many are in D's ancestor list).

--
Daniel Brockman <dan...@brockman.se>

Daniel Brockman

unread,
Jul 27, 2005, 9:28:43 PM7/27/05
to
"Ara.T.Howard" <Ara.T....@noaa.gov> writes:

> i was doing too much at once. all i was trying to say
> was that
>
> B < A
>
> means inheritence. if you also want to be able to
>
> class B
> include A
> include Z
> end
>
> and have that also mean inheritecne - then multiple
> inheritence must be addressed.

In what way must anything new be addressed?

> my point is simply that i don't think you can unify
> modules and classes without also intrducing multiple
> inheritence

Of course not. Indeed, many people consider Ruby's mixins
to already be a form of MI.

> you can't currently do this
>
> http://en.wikipedia.org/wiki/Diamond_problem
>
> with mixins.

Here we go again...

module A
def foo(bar) puts(bar) end
end

mobule B
include A
def foo ; super(123) end
end

module C
include A
def foo ; super(456) end
end

class D
include B
include C
end

> if unification took place you could.

Indeed, you still could.

>> How is multiple inheritance far less powerful
>> than mixins?
>
> because people don't use it well -

Even if that were proved true, it still wouldn't imply that
multiple inheritance is “far less powerful” than mixins.

> it's complexity precludes average programers using it in
> the very situations where it could be most benefit..

What alleged complexity are you talking about?

Is it simply that there would be no concept of superclass,
and hence no way to automatically draw an inheritance tree?

Unifying modules and classes will not force you to inherit
from String, Integer, Hash and IO at the same time.

You could still do everything you do now, with no
added complexity.

> just at it's prevelance in languages which support i and
> compare that to the useage of mixins in ruby, for example.

If you see a way to make a useful comparison, please do.

> mixins are powerful because they provide 90% of the
> functionality of mi

Agreed.

> with 10% of the debugging.

That, however, is a completely unsubstantiated and IMHO
outrageous claim. (Maybe I should counter it by claiming
that MI is powerful because it provides 110% of the
functionality of mixins, with only 10% of the debugging.)

> this is primarily because it's easy to affect the method
> search tree.

I don't understand this. What do you mean?

--
Daniel Brockman <dan...@brockman.se>

Austin Ziegler

unread,
Jul 27, 2005, 9:47:57 PM7/27/05
to
On 7/27/05, Daniel Brockman <dan...@brockman.se> wrote:
> gabriele renzi <surren...@remove-yahoo.it> writes:
> > you don't have a network of mixins, just a tree
> This is just plain wrong. Mixin inheritance networks can
> come in the shape of any directed acyclic graph.

Except that, in Ruby, it's all made into a tree.

-austin
--
Austin Ziegler * halos...@gmail.com
* Alternate: aus...@halostatue.ca


Yukihiro Matsumoto

unread,
Jul 27, 2005, 9:57:56 PM7/27/05
to
Hi,

In message "Re: What's so special about operators, built-in classes and modules?"

on Thu, 28 Jul 2005 09:42:54 +0900, Daniel Brockman <dan...@brockman.se> writes:

|> you don't have a network of mixins, just a tree
|
|This is just plain wrong. Mixin inheritance networks can
|come in the shape of any directed acyclic graph.

If you treat classes and modules equally as graph nodes. But if you
focus on classes, they form a simple tree, with leaves (modules)
attached to them. Besides that, there's no diamond inheritance in
Mixin inheritance.

matz.


Devin Mullins

unread,
Jul 27, 2005, 10:57:32 PM7/27/05
to
Yukihiro Matsumoto wrote:

>If you treat classes and modules equally as graph nodes. But if you
>focus on classes, they form a simple tree, with leaves (modules)
>attached to them. Besides that, there's no diamond inheritance in
>Mixin inheritance.
>
>

What would be bad about allowing the include method to take Classes in
addition to Modules? (And to keep everything else the same, including
the distinction between subclassing (via "<") and mixin-ing (via
"include").)

If nothing, then what would be the reason to keep Modules around?

Devin

Yukihiro Matsumoto

unread,
Jul 27, 2005, 11:14:58 PM7/27/05
to
Hi,

In message "Re: What's so special about operators, built-in classes and modules?"

on Thu, 28 Jul 2005 11:57:32 +0900, Devin Mullins <twi...@comcast.net> writes:

|What would be bad about allowing the include method to take Classes in
|addition to Modules? (And to keep everything else the same, including
|the distinction between subclassing (via "<") and mixin-ing (via
|"include").)

If we allow "include" to take classes, it's a plain multiple
inheritance. We should stand all the complexity of multiple
inheritance by that. I might have misunderstood you since I'm not
sure what you meant by "keeping everything else the same".

matz.


James Edward Gray II

unread,
Jul 27, 2005, 11:16:40 PM7/27/05
to
On Jul 27, 2005, at 9:57 PM, Devin Mullins wrote:

> What would be bad about allowing the include method to take Classes
> in addition to Modules? (And to keep everything else the same,
> including the distinction between subclassing (via "<") and mixin-
> ing (via "include").)
>
> If nothing, then what would be the reason to keep Modules around?

My opinion is that it's good to have two different types there, if
only for distinction. I can imagine the questions of, "Did I include
that class or just inherit from it?"

That's just my opinion though.

James Edward Gray II


Austin Ziegler

unread,
Jul 27, 2005, 11:19:33 PM7/27/05
to

I agree. The problem I have with this sort of proposal is that since
classes keep state, if we allow the inclusion of Class objects, then
we have to start worrying about the inheritance of that state, just
like we do with normal Class inheritance.

C++ MI sucks. Java interfaces suck. Ruby has it just right.

Devin Mullins

unread,
Jul 28, 2005, 12:14:49 AM7/28/05
to
Yukihiro Matsumoto wrote:

>|What would be bad about allowing the include method to take Classes in
>|addition to Modules? (And to keep everything else the same, including
>|the distinction between subclassing (via "<") and mixin-ing (via
>|"include").)
>
>If we allow "include" to take classes, it's a plain multiple
>inheritance.
>

If that were true, then your previous statement wouldn't be true:


"Besides that, there's no diamond inheritance in Mixin inheritance."

If we make the include method act the same on Classes as it does on
Modules (that is, to call #append_features, which, in turn, adds the
constants, methods, and module variables of the included class to the
receiving class), then that's just Mixin inheritance on Class objects.

> We should stand all the complexity of multiple
>inheritance by that.
>

I don't see "module Enumerable; ... end" as being simpler than "class
Enumerable; ... end". Am I missing something?

> I might have misunderstood you since I'm not
>sure what you meant by "keeping everything else the same".
>
>

Specifically, running include on a Class doesn't modify self.superclass,
and the super keyword would still try to talk to the actual superclass,
and not anything being mixed in, just like is the case with Modules.
Probably other things, too, but my mind is a little fuzzy right now.

Granted, weird things would happen if someone tried to include Array,
but weird things happen now when someone tries to subclass Array.
Allowing Classes to be included would be backward compatible (except for
code that actually _intends_ to raise a TypeError), and so your core and
std libs would be the same. As such, I don't see the comparison to C++'s
wacky IO inheritance graph as valid.

Well, even if your mind is set, matz, I appreciate your listening. In
all fairness, I /don't/ have a use case waiting in the hangar, should
classes and modules one day unify. :)

The following is really ugly, and completely untested, but might
demonstrate my intent:

require 'ruby2ruby' #see http://dark.fhtr.org/ruby2ruby.rb
#or http://blog.zenspider.com/archives/2005/02/rubytoruby.html

class Module
alias_method :orig_include, :include
def include(*mods)
classes, mods = mods.partition {|m| m.is_a? Class}
classes.each {|klass| klass.append_features(self)}
orig_include(mods)
end
end

class Class
def append_features(mod)
constants.each {|const| mod.const_set(const,const_get(const))}
class_variables.each do |var|
value = eval "@@#{var}"
mod.class_eval { @@temp = value }
mod.class_eval "@@#{var} = @@temp"
end
instance_methods.each do |meth|
mod.class_eval instance_method(meth).to_ruby
end
end
end

I also might be doing things the stupid ways at times. So sue me.

Thanks,
Devin

Devin Mullins

unread,
Jul 28, 2005, 12:21:13 AM7/28/05
to
James Edward Gray II wrote:

> My opinion is that it's good to have two different types there, if
> only for distinction. I can imagine the questions of, "Did I include
> that class or just inherit from it?"

I understand that argument. My only counter-argument is that, in
situations like that, Ruby has previously erred on the side of "write
better documentation, you nimcompoop!" But I'm not sure that's really a
good counter-argument.

>The problem I have with this sort of proposal is that since
>classes keep state, if we allow the inclusion of Class objects, then
>we have to start worrying about the inheritance of that state, just
>like we do with normal Class inheritance.
>

I don't understand that argument. In the context of being "include"d,
Modules keep state, and suffer from no less than would Classes, if
includable, as far as I can tell. What am I forgetting?

Devin

Yukihiro Matsumoto

unread,
Jul 28, 2005, 12:46:03 AM7/28/05
to
Hi,

In message "Re: What's so special about operators, built-in classes and modules?"

on Thu, 28 Jul 2005 13:14:49 +0900, Devin Mullins <twi...@comcast.net> writes:

|>If we allow "include" to take classes, it's a plain multiple
|>inheritance.
|>
|If that were true, then your previous statement wouldn't be true:
|"Besides that, there's no diamond inheritance in Mixin inheritance."

Would it?

|If we make the include method act the same on Classes as it does on
|Modules (that is, to call #append_features, which, in turn, adds the
|constants, methods, and module variables of the included class to the
|receiving class), then that's just Mixin inheritance on Class objects.

I'm sorry that I don't get it. We call it mixin inheritance because
mixin (modules) have some restrictions over classes:

* no superclass (although including other mixin is allowed)
* no instance

which make mixin inheritance as it is. Allowing "include" method to
include classes removes above restrictions. Then that's no different
from multiple inheritance, in my opinion.

I know there's some drawbacks in the current implementation of Ruby's
mixin inheritance, when a module is included repeatedly. I am willing
to fix it. I'm seeking the best way to fix.

Besides all of them, I don't understand why this issue arise again and
again. _I_ encourage mixin inheritance. It is powerful enough to
solve the problem in single inheritance (sharing code between classes
beyond inheritance line, without copy&paste). It is much simpler and
easier to use than multiple inheritance. Why people want "real"
multiple inheritance by unifying classes and modules, when Ruby's
mixin inheritance works quite well? Why people want unnecessary
complexity? Just because other languages do? I'm curious.

Interestingly, a few have complained for the lack of goto in
Ruby. Goto is much more powerful control structure than while, break,
next, etc. We can construct others using goto. I wander why no one
propose to unify them. ...No, Don't. I will refuse.

matz.


Devin Mullins

unread,
Jul 28, 2005, 12:47:30 AM7/28/05
to
Devin Mullins wrote:

> require 'ruby2ruby' #see http://dark.fhtr.org/ruby2ruby.rb
> #or http://blog.zenspider.com/archives/2005/02/rubytoruby.html
>
> class Module
> alias_method :orig_include, :include
> def include(*mods)
> classes, mods = mods.partition {|m| m.is_a? Class}
> classes.each {|klass| klass.append_features(self)}
> orig_include(mods)
> end
> end
>
> class Class
> def append_features(mod)
> constants.each {|const| mod.const_set(const,const_get(const))}
> class_variables.each do |var|
> value = eval "@@#{var}"
> mod.class_eval { @@temp = value }
> mod.class_eval "@@#{var} = @@temp"
> end
> instance_methods.each do |meth|
> mod.class_eval instance_method(meth).to_ruby
> end
> end
> end
>

Oops, make that:
..
instance_methods.each do |meth|
mod.class_eval instance_method(meth).to_ruby unless
mod.method_defined?(meth)
end
..

Devin

Devin Mullins

unread,
Jul 28, 2005, 1:03:08 AM7/28/05
to
Yukihiro Matsumoto wrote:

>I'm sorry that I don't get it. We call it mixin inheritance because
>mixin (modules) have some restrictions over classes:
>
> * no superclass (although including other mixin is allowed)
> * no instance
>
>which make mixin inheritance as it is. Allowing "include" method to
>include classes removes above restrictions. Then that's no different
>from multiple inheritance, in my opinion.
>
>

OK. It sounds like you're laying down the law and prohibiting a certain
course of action because you think it's ugly, not because it's hard to
implement clearly and unamiguously. That's fine. I respect that. Good to
know. :)

>Besides all of them, I don't understand why this issue arise again and
>again.
>

'Cause it's a mailing list, and we like to complain! Also, I'm new here,
so I wasn't around for the last flurry.

> _I_ encourage mixin inheritance. It is powerful enough to
>solve the problem in single inheritance (sharing code between classes
>beyond inheritance line, without copy&paste).
>

Agreed.

> Why people want "real"
>multiple inheritance by unifying classes and modules, when Ruby's
>mixin inheritance works quite well? Why people want unnecessary
>complexity? Just because other languages do? I'm curious.
>
>

My main driver was that the relationship between Module and Class is
confusing. Everything else was just intellectual flight-of-fancy, and I
apologize if I made it sound otherwise, or if I pissed you off.

>Interestingly, a few have complained for the lack of goto in
>Ruby. Goto is much more powerful control structure than while, break,
>next, etc. We can construct others using goto. I wander why no one
>propose to unify them. ...No, Don't. I will refuse.
>
>

Yep. It definitely sounds like you're laying down the law and
prohibiting a certain course of action because you think it's ugly. :)

Devin
..brownie points if you notice the thing about this email that I don't
want you to notice...

Nikolai Weibull

unread,
Jul 28, 2005, 6:07:27 AM7/28/05
to
Austin Ziegler wrote:

> C++ MI sucks. Java interfaces suck. Ruby has it just right.

How about CLOS?,

Austin Ziegler

unread,
Jul 28, 2005, 8:09:49 AM7/28/05
to
On 7/28/05, Devin Mullins <twi...@comcast.net> wrote:
> >The problem I have with this sort of proposal is that since
> >classes keep state, if we allow the inclusion of Class objects, then
> >we have to start worrying about the inheritance of that state, just
> >like we do with normal Class inheritance.
> I don't understand that argument. In the context of being "include"d,
> Modules keep state, and suffer from no less than would Classes, if
> includable, as far as I can tell. What am I forgetting?

FYI, your quoting mechanism is off. IIRC, I wrote that, not James.
When a module is mixed into a class, its references to instance
variables are bound to the instance of the class.

module Foo
def baz
@baz ||= 0
@baz += 1
end
end

class Bar
include Foo
def blat
@blat ||= 0
@blat += 1
end
end

moof = Bar.new
moof.instance_variables # => []
moof.blat; moof.instance_variables # => ["@blat"]
moof.baz; moof.instance_variables # => ["@blat", "@baz"]

If we include classes, then we have to start caring about the origin
of instance variables.

Austin Ziegler

unread,
Jul 28, 2005, 8:16:05 AM7/28/05
to
On 7/28/05, Yukihiro Matsumoto <ma...@ruby-lang.org> wrote:
> Besides all of them, I don't understand why this issue arise again
> and again. _I_ encourage mixin inheritance. It is powerful enough
> to solve the problem in single inheritance (sharing code between
> classes beyond inheritance line, without copy&paste). It is much
> simpler and easier to use than multiple inheritance. Why people
> want "real" multiple inheritance by unifying classes and modules,
> when Ruby's mixin inheritance works quite well? Why people want
> unnecessary complexity? Just because other languages do? I'm
> curious.

This is just my opinion, Matz, and not any particular insight into
Daniel's or Devin's thinking, but it's based on the common patterns
that I've seen between people who tend to advocate the unification
of class and module.

It seems to me that these people are interested in Ruby becoming
theoretically conceptually clean as well as pragmatically clean. It
seems to me that they're saying "these things are *almost* the same;
why can't they be the same?" This is without regard for the
practical problems of such unification, but purely for the aesthetic
theoretical cleanliness.

This is part of the reason I responded to Daniel a while back saying
that I couldn't see a single reason for the unification of the two
concepts. I still can't.

Austin Ziegler

unread,
Jul 28, 2005, 8:18:08 AM7/28/05
to
On 7/28/05, Nikolai Weibull

<mailing-lis...@rawuncut.elitemail.org> wrote:
> Austin Ziegler wrote:
>> C++ MI sucks. Java interfaces suck. Ruby has it just right.
> How about CLOS?,

I don't know Lisp; I don't know CLOS. I can't answer toward that. I
have an aversion to Lisp after one too many elisp hacking sessions
before I discovered what a pile emacs is ;)

No, seriously, I haven't had a reason to learn Lisp, Paul Graham
aside. It took me a while to get into Ruby, too, because I didn't have
a project for it. Now I have too many ;)

Jim Weirich

unread,
Jul 28, 2005, 9:25:36 AM7/28/05
to

Austin Ziegler said:
> When a module is mixed into a class, its references to instance
> variables are bound to the instance of the class.
>
> module Foo
> def baz
> @baz ||= 0
> @baz += 1
> end
> end
>
> class Bar
> include Foo
> def blat
> @blat ||= 0
> @blat += 1
> end
> end
>
> moof = Bar.new
> moof.instance_variables # => []
> moof.blat; moof.instance_variables # => ["@blat"]
> moof.baz; moof.instance_variables # => ["@blat", "@baz"]
>
> If we include classes, then we have to start caring about the origin
> of instance variables.

How would the above output be different if Bar were a class and we
inherited from Bar?

--
-- Jim Weirich j...@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"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)

Ara.T.Howard

unread,
Jul 28, 2005, 10:35:38 AM7/28/05
to

Ara.T.Howard

unread,
Jul 28, 2005, 10:48:17 AM7/28/05
to
On Thu, 28 Jul 2005, Daniel Brockman wrote:

> As has been pointed out countless times already, the diamond inheritance
> problem already exists in Ruby:
>
> module A
> def initialize(val)
> @var = val
> end
> end
>
> module B
> include A
> def initialize
> super(5)
> end
> end
>
> module C
> include A
> def initialize
> super(42)
> end
> end
>
> class D
> include B
> include C
> end


did you run this? this is most defintely __not__ the diamond problem - it is
strictly a tree:

harp:~ > cat a.rb
module A
def initialize(val)
p 'in A'


@var = val
end
end

module B
include A
def initialize(*a)
p 'in B'
super(5)
end
end

module C
include A
def initialize(*a)
p 'in C'
super(42)
end
end

class D
include B
end

p D::new

class D
include C
end

p D::new


harp:~ > ruby a.rb
"in B"
"in A"
#<D:0xb75ce160 @var=5>
"in C"
"in B"
"in A"
#<D:0xb75ce05c @var=5>

if this were the diamond problem ruby would have needed to choose between
__either__ the 'initialize' in B or C but, because we are walking a tree, it
simply does both - each 'include' statement is adding depth to the search but
it never becomes a complex graph that needs an algorithim which resolves
conflicts. see

http://en.wikipedia.org/wiki/Diamond_problem

for more on this. again - there no ambiguity in which 'initialize' ruby calls
(both) and therefore no diamond problem.

hth.

Jim Weirich

unread,
Jul 28, 2005, 11:49:16 AM7/28/05
to

From my point of view, it looks like a diamond include structure, i.e.

A
/ \
B C
\ /
D

Ruby does linearizes the method resolution order to D,C,B,A.

> if this were the diamond problem ruby would have needed to choose between
> __either__ the 'initialize' in B or C but,

Correct, and it chooses C (which in turn calls B because of the super in C).

> because we are walking a tree,
> it simply does both - each 'include' statement is adding depth to
> the search but it never becomes a complex graph that needs an
> algorithim which resolves conflicts.

Actually, there *is* an algorithm that reduces the graph to a simple
linear search. As modules are included, the included module's search
order is appended to the beginning of the new search order, minus any
modules that are already included.

In fact, Ruby's MRO algorithm for modules is very similar to Python's
(old[1]) MRO for multiple inheritance (except Ruby favors the last module
added last and Python favors the first class added).

> see
>
> http://en.wikipedia.org/wiki/Diamond_problem

I found this particular entry to be less helpful than other resources.
The problem is rarely which method to call (which actually is not a
diamond inheritance problem ... it can arise whenever two base classes
share a method with a common name). The big problem with diamond
inheritance is the question of instance data ... do you have one or two
copies?

(and given the way Ruby handles instance variables, I find it hard to
imagine the answer to this question would ever be two).

> for more on this. again - there no ambiguity in which 'initialize' ruby
> calls (both) and therefore no diamond problem.

--

-- Jim Weirich j...@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"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)

[1] I understand that modern Python supports a different algorithm than
the one described on the wikipedia page. See
http://www.python.org/2.3/mro.html for details.

Trans

unread,
Jul 28, 2005, 11:51:35 AM7/28/05
to

Ara.T.Howard wrote:
> because otherwise including module could clobber class methods which generally
> include hooks to create instances like 'new', 'instance', 'parse', etc. if you
> replace the set of methods responsible for stamping out instances you are not
> 'mixing-in' functionality to those instances - but changing what type those
> will be. there is a fundemental difference here.

That assumes no other way to deal with this "clobbering" is utilized. I
think your overstating to say there is a fundemental difference. It
still boils down to the "Duck" --walk, talk and all that.

> > No, it would not be possible to retain full backwards compatibility, but I
> > cannot think of a real-world case in which actual problems would result.
>

> added multiple inheritence semantics for module inclusion would not be
> backwards compatibile imho.

What would break? BTW I think that handling this kind of "MI" would be
fairly straight forward with ancestor directed calls (eg.
AModule\amethod)

2c,

T.

Ara.T.Howard

unread,
Jul 28, 2005, 12:26:45 PM7/28/05
to
On Fri, 29 Jul 2005, Jim Weirich wrote:

>> did you run this? this is most defintely __not__ the diamond problem - it
>> is strictly a tree:
>
>> From my point of view, it looks like a diamond include structure, i.e.
>
> A
> / \
> B C
> \ /
> D
>
> Ruby does linearizes the method resolution order to D,C,B,A.

right - we are saying the same thing - the diamond is reduced to a line - ergo
no 'diamond' problem - it's avoided by requiring the programmer to order the
line via 'include'.

>> because we are walking a tree,
>> it simply does both - each 'include' statement is adding depth to
>> the search but it never becomes a complex graph that needs an
>> algorithim which resolves conflicts.
>
> Actually, there *is* an algorithm that reduces the graph to a simple linear
> search. As modules are included, the included module's search order is
> appended to the beginning of the new search order, minus any modules that
> are already included.
>
> In fact, Ruby's MRO algorithm for modules is very similar to Python's
> (old[1]) MRO for multiple inheritance (except Ruby favors the last module
> added last and Python favors the first class added).

this is definitely more correct...

>> http://en.wikipedia.org/wiki/Diamond_problem
>
> I found this particular entry to be less helpful than other resources. The
> problem is rarely which method to call (which actually is not a diamond
> inheritance problem ... it can arise whenever two base classes share a
> method with a common name). The big problem with diamond inheritance is the
> question of instance data ... do you have one or two copies?

sure... i just wast just trying to help the OP see that we currently never
actually end up with diamonds (tree does not degrade to graph) that require
ruby to resolve the search order. currently it is entirely up to programmer
who can chose based on the order of module inclusion. for classes it's even
simpler. in otherwords the search order is always totally explicit and shown
in the source rather than implicit as defined by some search algorithim used
by the interpreter... and, by extension, that making 'include' mean 'inherit'
would indeed setup a diamond issue that ruby would need to handle implicitly
(mi). of course there are possibly other solutions...

> (and given the way Ruby handles instance variables, I find it hard to
> imagine the answer to this question would ever be two).

that would certainly be confusing...

cheers.

Ara.T.Howard

unread,
Jul 28, 2005, 12:31:56 PM7/28/05
to
On Fri, 29 Jul 2005, Trans wrote:

>
> Ara.T.Howard wrote:
>> because otherwise including module could clobber class methods which generally
>> include hooks to create instances like 'new', 'instance', 'parse', etc. if you
>> replace the set of methods responsible for stamping out instances you are not
>> 'mixing-in' functionality to those instances - but changing what type those
>> will be. there is a fundemental difference here.
>
> That assumes no other way to deal with this "clobbering" is utilized. I
> think your overstating to say there is a fundemental difference. It
> still boils down to the "Duck" --walk, talk and all that.

i'm not sure i agree - so long as ruby has types/classes/whatever returning a
different kind of one sure seems alot different than returning a specialzation
(subclass) of one. however 'type' is pretty muddy in ruby as we all agree.

>>> No, it would not be possible to retain full backwards compatibility, but I
>>> cannot think of a real-world case in which actual problems would result.
>>
>> added multiple inheritence semantics for module inclusion would not be
>> backwards compatibile imho.
>
> What would break?

i've given some examples in this thread from my own code... i assume there
would be more.

> BTW I think that handling this kind of "MI" would be fairly straight forward
> with ancestor directed calls (eg. AModule\amethod)

sure - it could be done. but only by matz.

Joel VanderWerf

unread,
Jul 28, 2005, 1:04:30 PM7/28/05
to
Jim Weirich wrote:

> I found this particular entry to be less helpful than other resources.
> The problem is rarely which method to call (which actually is not a
> diamond inheritance problem ... it can arise whenever two base classes
> share a method with a common name). The big problem with diamond
> inheritance is the question of instance data ... do you have one or two
> copies?
>
> (and given the way Ruby handles instance variables, I find it hard to
> imagine the answer to this question would ever be two).

Dim memory... wasn't there a proposal to have per-module (or class)
instance variables, so that different parts of the inheritance chain
don't step on each other?

Wouldn't this introduce the diamond problem?

Take a case like this:

module Counts
def inc
@count ||= 0
@count += 1
end

def cur
@count
end
end

module CountsDucks
include Counts

def saw_a_duck
inc
end

def duck_count
cur
end
end

module CountsChickens
include Counts

def saw_a_chicken
inc
end

def chicken_count
cur
end
end

class C
include CountsDucks
include CountsChickens
end

c = C.new

c.saw_a_duck
c.saw_a_duck
c.saw_a_chicken

p c.duck_count
p c.chicken_count


Now, the output is

3
3

But using per-module instance variables, you would want this to be

2
1

This seems like a case where you would want there to be two copies of
the (ivars defined by the) Counts module.


Daniel Brockman

unread,
Jul 28, 2005, 7:31:05 PM7/28/05
to
Yukihiro Matsumoto <ma...@ruby-lang.org> writes:

Matz> I don't understand why this issue [class/module
Matz> unification] arises again and again.

I know that the issue has come up a number of times before,
and that you have been opposed to the idea each time.
I appreciate that you let people like me continue to whine
about it on this list. (If this were emacs-devel, RMS would
have killed this thread the minute he saw it emerge.)

Matz> _I_ encourage mixin inheritance.

Yes, and that's the strongest argument in favor of mixins
(i.e., separate non-class modules) that I've seen so far.

Matz> It is powerful enough to solve the problem in single
Matz> inheritance (sharing code between classes beyond
Matz> inheritance line, without copy&paste).

Agreed. It *is* powerful enough.

Matz> It is much simpler and easier to use than
Matz> multiple inheritance.

This is where our minds go apart. Is it because unifying
classes and modules would *enable* you to do weird things
like inheriting from both Array and Hash? I honestly don't
think anyone ever tried to do that, and I don't think anyone
would expect it to work in a useful manner. Do you?

(Yes, I'm beating at a straw man here, but I'm only doing it
because I don't see anything else around to beat at.)

Matz> Why people want "real" multiple inheritance by
Matz> unifying classes and modules, when Ruby's mixin
Matz> inheritance works quite well?

Because it would do the same thing, only in a simpler way.
I hesitate to invoke Occam's Razor, but it's definitely
about orthogonality of concepts.

Matz> Why people want unnecessary complexity?
Matz> Just because other languages do? I'm curious.

Unnecessary complexity is exactly what I do *not* want.
I am under the belief that we currently have it.


Austin Ziegler <halos...@gmail.com> writes:

AZ> This is just my opinion, Matz, and not any particular
AZ> insight into Daniel's or Devin's thinking, but it's
AZ> based on the common patterns that I've seen between
AZ> people who tend to advocate the unification of class
AZ> and module.
AZ>
AZ> It seems to me that these people are interested in Ruby
AZ> becoming theoretically conceptually clean as well as
AZ> pragmatically clean.

That's a nice way of putting it, but I'd put it in terms of
orthogonality instead of cleanliness, because "clean" is
such a loaded and inexact word.

[Using ASCII quotes now, Nikolai, out of respect to everyone
who can't deal with Unicode. I'll annoy them more later.]

AZ> It seems to me that they're saying "these things are
AZ> *almost* the same; why can't they be the same?"

Exactly. At least, that's what I'm thinking. :-)

AZ> This is without regard for the practical problems of
AZ> such unification, but purely for the aesthetic
AZ> theoretical cleanliness.

Ignoring for a while the fact that theoretical uncleanliness
is itself a practical problem for whoever is confused by it,
I am more than willing to discuss the practical problems of
the unification (and I'm sure there are some).

AZ> This is part of the reason I responded to Daniel a while
AZ> back saying that I couldn't see a single reason for the
AZ> unification of the two concepts. I still can't.

To which I replied that you were "forcing me to assume that
you were shying away from the truth." I regret using such
harsh language, because I later realized that when you said
that you "can't see a single reason," you didn't mean that
you ignored the reasons I was putting before you, but that
you were simply unconvinced by them.

Austin, if I offended you, I sincerely apologize.

--
Daniel Brockman <dan...@brockman.se>

So really, we all have to ask ourselves:
Am I waiting for RMS to do this? --TTN.

Yukihiro Matsumoto

unread,
Jul 28, 2005, 7:46:54 PM7/28/05
to
Hi,

In message "Re: What's so special about operators, built-in classes and modules?"

on Fri, 29 Jul 2005 08:31:05 +0900, Daniel Brockman <dan...@brockman.se> writes:

|Matz> It is much simpler and easier to use than
|Matz> multiple inheritance.
|
|This is where our minds go apart. Is it because unifying
|classes and modules would *enable* you to do weird things
|like inheriting from both Array and Hash? I honestly don't
|think anyone ever tried to do that, and I don't think anyone
|would expect it to work in a useful manner. Do you?

If it is not impossible, the language should define the behavior for
it. If it is possible to inherit from Array and Hash, _I_ have to do
something. Unifying them gives me too heavy burden.

|Matz> Why people want "real" multiple inheritance by
|Matz> unifying classes and modules, when Ruby's mixin
|Matz> inheritance works quite well?
|
|Because it would do the same thing, only in a simpler way.
|I hesitate to invoke Occam's Razor, but it's definitely
|about orthogonality of concepts.

Pardon me? You feel multiple inheritance simpler?

It has fewer restriction, more general, but not simpler, both in
concept and implementation. Perhaps we are using the term "simple" in
different manner.

When they would do almost the same thing, and when mixin inheritance
is much simpler to understand (for me at least), far easier to
implement, why should I implement multiple inheritance?

matz.


Ara.T.Howard

unread,
Jul 28, 2005, 8:28:53 PM7/28/05
to
On Fri, 29 Jul 2005, Yukihiro Matsumoto wrote:

> When they would do almost the same thing, and when mixin inheritance is much
> simpler to understand (for me at least), far easier to implement, why should
> I implement multiple inheritance?

well - it would end this thread. ;-)

ps. you may have seen that i'm working on a book about scientific programming
with ruby (published by the pragmatic programmers); a bulk of the book will be
formed around case studies, some of which we've already started. it turns out
people are doing some pretty interesting science with ruby

http://sciruby.codeforpeople.com/sr.cgi/InterestingPeople

in you know of any others, especially in japan, or have any other input please
don't hesitate to let me know.

Trans

unread,
Jul 28, 2005, 8:36:09 PM7/28/05
to
matz wrote:
> When they would do almost the same thing, and when mixin inheritance
> is much simpler to understand (for me at least), far easier to
> implement, why should I implement multiple inheritance?

If I may, I don't think you should implement MI. Yet neither do I think
a differentiation between class and module is neccessary. I think this
is the common point of view of those who think calss and module should
be merged, but that view continuly gets lost in the MI talk. I'm all
for Ruby's SI with mixins, but the effects ought to be in the usage,
not in the name. Consider something like this (yes, this is made up on
the spot so don't be too hard on it).

class Identity
attr_accessor :username, :password, :public_key, :realname
end

class Location
attr :address1, :address2, :city, :state, :zipcode
end

One may have been happily using these classes independently for some
time, then one day decide it would be nice to REUSE them in another
class:

class Customer
include Identity
include Demographic
attr_accessor :subscriptions
end

But of course you cannot do this. At least one of these former classes
would need to be a module. Well you _can_ WORK AROUND.

module IdentityMod
attr_accessor :username, :password, :public_key, :realname
end

class Identity
include IdentityMod
end

class LocationMod
attr :address1, :address2, :city, :state, :zipcode
end

class Location
include LocationMod
end

That'll do it. But wait since I was able to WORK AROUND it, what was
the point of preventing the original code form? Hmm? In the end it
amounts to essentially same thing. Distigushing between a class and a
module strictly by _decleration_ creates frivolous restraints. That's
why I think it better to distinguish by usage, not by name.

Thanks,
T.

Daniel Brockman

unread,
Jul 28, 2005, 8:43:44 PM7/28/05
to
Austin Ziegler <halos...@gmail.com> writes:

> If we include classes, then we have to start caring about
> the origin of instance variables.

You already have to care about the origin of instance
variables when subclassing. What's the difference?

--
Daniel Brockman <dan...@brockman.se>

Trans

unread,
Jul 28, 2005, 9:00:50 PM7/28/05
to
oops...

s/class LocationMod/module LocationMod/

T.

Daniel Brockman

unread,
Jul 28, 2005, 9:28:56 PM7/28/05
to
GR> you don't have a network of mixins, just a tree

DB> This is just plain wrong. Mixin inheritance networks
DB> can come in the shape of any directed acyclic graph.

AZ> Except that, in Ruby, it's all made into a tree.

Excuse me? Using a shorthand notation for Module#include,

module A ; end
module B < A ; end
module C < A ; end
module D < B, C ; end

where is the graph "made into a tree"?

Are you talking about the linearization of superclasses and
included modules? In which case, why do you say "tree"?

--
Daniel Brockman <dan...@brockman.se>

Daniel Brockman

unread,
Jul 28, 2005, 10:00:47 PM7/28/05
to
Yukihiro Matsumoto <ma...@ruby-lang.org> writes:

>> Mixin inheritance networks can come in the shape of any
>> directed acyclic graph.
>
> If you treat classes and modules equally as graph nodes.

You don't even have to involve classes. Just modules alone
can form an inheritance network in the shape of any DAC.

> But if you focus on classes, they form a simple tree,
> with leaves (modules) attached to them.

Agreed. Classes can only form trees.

> Besides that, there's no diamond inheritance in
> Mixin inheritance.

This comes up again and again, and I never understand it.
Two years ago, you claimed the same thing:

> This combination is indeed a restricted multiple
> inheritance. [Thanks to single class inheritance],
> we won't have diamond inheritance problem,

Mathieu Bouchard replied[1],

>>> module A; end
>>> module B; include A; end
>>> module C; include A; end
>>> class D; include C,B; end
>>>
>>> This is a diamond inheritance pattern.

but you never replied back to him.

I'd appreciate it if someone could clarify once and for all
how the diamond inheritance problem doesn't exist in Ruby.

--
Daniel Brockman <dan...@brockman.se>

[1] <http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-core/1472>

Daniel Brockman

unread,
Jul 28, 2005, 10:15:38 PM7/28/05
to
Yukihiro Matsumoto <ma...@ruby-lang.org> writes:

> Goto is much more powerful control structure than while,
> break, next, etc. We can construct others using goto.
> I wander why no one propose to unify them.

I would assume it's precisely because "goto is a much more
powerful control structure" that noone has proposed to unify
it with while, break and next. It wouldn't make sense.

With classes and modules, it's the exact opposite: The one
is *not* much more powerful than the other; they are so much
alike that people are proposing to unify them.

--
Daniel Brockman <dan...@brockman.se>

Trans

unread,
Jul 28, 2005, 10:21:11 PM7/28/05
to

Daniel Brockman wrote:
> Mathieu Bouchard replied[1],
>
> >>> module A; end
> >>> module B; include A; end
> >>> module C; include A; end
> >>> class D; include C,B; end
> >>>
> >>> This is a diamond inheritance pattern.
>
> but you never replied back to him.
>
> I'd appreciate it if someone could clarify once and for all
> how the diamond inheritance problem doesn't exist in Ruby.

B/c ruby _linearizes_ the inclusions.

irb(main):001:0> module A; end
=> nil
irb(main):002:0> module B; include A; end
=> B
irb(main):003:0> module C; include A; end
=> C
irb(main):004:0> class D; include C,B ; end
=> D
irb(main):005:0> D.ancestors
=> [D, C, B, A, Object, Kernel]

Method lookup will proceed in that order.

HTH,
T.

Jim Weirich

unread,
Jul 28, 2005, 11:04:39 PM7/28/05
to
[Warning ... I'm afraid I got a bit long winded ... sorry]

On Thursday 28 July 2005 10:00 pm, Daniel Brockman wrote:
> I'd appreciate it if someone could clarify once and for all
> how the diamond inheritance problem doesn't exist in Ruby.

First, some clarification: What is the problem with diamond inheritance?
Diamond inheritance is a pattern of MI that has a parent class (or module in
Ruby's case) that is reachable via different inheritance paths. The specific
term for this is Repeated Inheritance.

The basic problem with Repeated Inheritance is how instance variables defined
in the repeated class should be handled. Should there be one copy total, or
one copy for each repeated parent class.

(An aside: Another thread on this topic indicated that method resolution was
a problem in repeated inheritance. That is incorrect, it is an issue in any
form of multiple inheritance (even the module variety), and does not specific
to repeated inheritance).

Ok, now that we've clarified the question, we can answer it: Why isn't
repeated inheritance a problem with modules?

Some people will say its because modules don't define state. Although
correct, its misleading because it implies that classes do define state.
Classes (in Ruby) don't define state either.

Wait a minute, let me say that in a better way!

Module (and Classes) in Ruby don't contain any /instance/ state. The instance
variables in a ruby object are managed by the instance itself, not the
classes. This is different from most other OO languages.

Most other languages think of objects as little areas of memory. Consider a
class B that inherits from A. Its memory layout would look something like
this:

|<--- A --->|
|<------------- B ------>|

The memory for the A part of the object takes up the first section of memory
of a B object. In fact, someone looking at the beginning of the B object
would see a real, live A object in memory. That's how polymorphism works in
languages like C++.

When you have repeated inheritance, the whole memory layout scheme gets all
screwed up. Lets introduce two new classes, C which also inherits from A,
and D which multiply inherits from B and C. What does the memory layout of D
look like?

|<--- A --->| |<--- A --->|
|<------------- B ------>|<------------- C -------->|
|<------------------------------------------------------ D --->|

Yep, two copies of A. One for B and one for C. And that's the problem. Most
times you only want one copy of A.

Different languages handle the repeated inheritance differently. C++
introduces "virtual" inheritance, where the base class is not located in the
same memory area, but is (possibly) displaced. Java only allows MI in
interfaces (and since interfaces have no data memory layout, the problem
doesn't arise).

Eiffel has a flexible approach to repeated inheritance. Any feature (Eiffel's
term for methods and instance variables) that ends up with the same name in
the final class, gets only one copy of that feature. You can rename features
as you inherit, so if a feature ends up with two names in the final class,
you get two copies of it, each with its own name (so there is no ambiguity
either ... very clever). Eiffel's solution is very clean for the developer,
but really hard to implement correctly.

Getting back to Ruby ... The whole memory layout problem is brought about by
thinking of variables as shoeboxes which hold values. Once you have
shoeboxes, you got to pay attention to how you arrange them.

Ruby objects don't have a memory layout for the instance variables. In fact,
it is quite possible that two objects of the same class don't even have the
same instance variables.

So, in summary, why is diamond (repeated) inheritance not a problem in Ruby
modules?

Because the memory layout issues that force multiple copies of a base class
just don't exist in Ruby.

--

Jim Weirich

unread,
Jul 28, 2005, 11:21:03 PM7/28/05
to
On Thursday 28 July 2005 10:26 pm, Trans wrote:
> > I'd appreciate it if someone could clarify once and for all
> > how the diamond inheritance problem doesn't exist in Ruby.
>
> B/c ruby _linearizes_ the inclusions.

I am going to disagree. Linearization addresses MRO (method resolution
order), which has little to do with diamond inheritance. MRO problems occur
in general MI.

Diamond inheritance issues deal more with the repeated base class instance
variables. Ruby handles instance variables in such a way that repeated
inheritance in the diamond pattern is just not a problem. (See ... a short
version of my long winded answer elsewhere in this thread).

Daniel Brockman

unread,
Jul 28, 2005, 11:24:39 PM7/28/05
to
Thank you for keeping up Ara --- I'm enjoying this
discussion. :-)

"Ara.T.Howard" <Ara.T....@noaa.gov> writes:

> On Thu, 28 Jul 2005, Daniel Brockman wrote:
>

>>> i'd say __all__ code depends on that. otherwise
>>>
>>> module M
>>> def self::new
>>> raise
>>> end
>>> end
>>> class C
>>> include M
>>> end
>>>
>>> c = C::new
>>
>> Surely you are not suggesting that all code defines
>> singleton ‘new’ methods on modules?

What I meant by this was that your claim, "i'd say __all__
code depends on that," was a bit bold.

>> Considering that this doesn't work,
>>
>> class X
>> def self.new
>> raise
>> end
>> end
>>
>> class Y < X
>> end
>>
>> x = X.new
>>
>> why do you expect your example to work?
>
> well - you have to actually __use__ the method - i was
> pointing to the fact that they are inherited in the case
> of subclasses and are not in the case of mixins ;-)

Yes, and I was trying to ask you whether or not and *why*
you expect such a difference in behavior. (If you didn't
expect it, then you agree it is surprising?)

> harp:~ > cat a.rb
> class X
> def self.new
> raise
> end
> end
>
> class Y < X
> def self.new; super; end
> end
>
> x = X.new
>
> harp:~ > ruby a.rb
> a.rb:3:in `new': unhandled exception
> from a.rb:11
>
>
>> I don't get why Y's singleton class inherits from X's,
>> while C's *doesn't* inherit from M's.


>
> because otherwise including module could clobber class
> methods which generally include hooks to create instances
> like 'new', 'instance', 'parse', etc.

But you have already demonstrated that inheriting from a
class *can* clobber methods like Class#new. So I don't see
the difference. I know *what* happens; just not *why*.

class AbstractFoo
def self.new
raise "nope!"
end
end

class Foo < AbstractFoo
end

foo = Foo.new # error

class Foo
def self.new
# What do I put here?
end
end

Clearly this problem already exists for class inheritance.

> if you replace the set of methods responsible for stamping
> out instances you are not 'mixing-in' functionality to
> those instances -

(No, you are mixing in functionality to the *class*, not the
instances, though of course the latter refer to the former.)

> but changing what type those will be. there is a
> fundemental difference here.

You are making a *classic* bifurcation here: Your argument
boils down to, "you are changing what type the instances
will have, therefore you are not mixing in functionality,"
when in fact I am doing both.

It's like if I were to say that in your example,

> class X
> def self.new
> raise
> end
> end
>
> class Y < X
> def self.new; super; end
> end

the Y class is not inheriting from the X class, because it's
preventing instances from being created.

>> Why are you defining M.new? Do you have actual code that
>> does this?
>
> tons. [...]
>
> module Command
> class Abstract
> ...
> end
> class Load < Abstract
> ...
> end
> class Sub < Abstract
> ...
> end
> class Add < Abstract
> ...
> end
> class Store < Abstract
> ...
> end
> def self::new line
> orbit_normal_time, command, register, value = parse line
> klass =
> case command
> when /load/
> Load
> when /sub/
> Sub
> when /add/
> Add
> when /store/
> Store
> end
> klass::new(orbit_normal_time, register, value)
> end
> end
>
> class PayloadActivationMessage < AbstractMessage
> include Command
> end

Okay, thank you. I can see that a lot of similar code
probably exists. But the example you've given would not be
difficult to fix if module metaclass inheritance were added.

Actually, your code seems pretty fishy to me as it is:

command = Command.new(foo)
command.is_a? Command #=> false

I think it would have been a better idea to do this:

class Command
class Load < Command
...
end
class Sub < Command
...
end
class Add < Command
...
end
class Store < Command
...
end
def self::new line
orbit_normal_time, command, register, value = parse line
klass =
case command
when /load/
Load
when /sub/
Sub
when /add/
Add
when /store/
Store
end
klass::new(orbit_normal_time, register, value)
end
end

If you change your code in this way, the problem disappears;
in other words, your code is no longer an example of where
module metaclass inheritance is a problem.

It's useful to see actual code that would break, but it
would be even more useful to see actual, *non-fishy* code
that would break. So could you share any other examples?

> changing the notion of super is, be definition, a very
> strong form on inheritence.

Then it is your opinion that including a module is a "very
strong form of inheritence"?

> added multiple inheritence semantics for module inclusion
> would not be backwards compatibile imho.

What are "multiple inheritence semantics"?

--
Daniel Brockman <dan...@brockman.se>

Daniel Brockman

unread,
Jul 28, 2005, 11:53:53 PM7/28/05
to
"Ara.T.Howard" <Ara.T....@noaa.gov> writes:

> On Fri, 29 Jul 2005, Jim Weirich wrote:
>
>> The big problem with diamond inheritance is the question
>> of instance data ... do you have one or two copies?
>
> sure... i just wast just trying to help the OP see that we
> currently never actually end up with diamonds

Thank you, but I do understand the concept of linearization,
and maintain that it does not prevent diamond inheritance.

> that require ruby to resolve the search order.
> currently it is entirely up to programmer who can chose
> based on the order of module inclusion.

Why would it be any different if Class equalled Module?

> for classes it's even simpler. in otherwords the search
> order is always totally explicit and shown in the source
> rather than implicit as defined by some search algorithim
> used by the interpreter...

The unification would not change this at all, in any way.
Even if this syntax was added,

class A < B, C, D ; end

the order B, C, D would still be "totally explicit and shown
in the source."

> and, by extension, that making 'include' mean 'inherit'
> would indeed setup a diamond issue that ruby would need to
> handle implicitly (mi).

I don't understand this.

>> (and given the way Ruby handles instance variables, I
>> find it hard to imagine the answer to this question would
>> ever be two).
>
> that would certainly be confusing...

Don't knock it 'til you try it. As Joel said, there's been
talk of adding module-local instance variables.

It seems we've finally been able to agree that Ruby does
have diamond inheritance, and adding module-local instance
variables would introduce a diamond-inheritance-related
problem, but that problem is wholly unrelated to the
class/module distinction.

In fact, as irony would have it, that diamond inheritance
problem would *only* affect modules, not classes!

--
Daniel Brockman <dan...@brockman.se>

Eric Mahurin

unread,
Jul 29, 2005, 12:06:08 AM7/29/05
to
Daniel,

I haven't really followed this VERY long thread completely, but
I'd thought I'd jump in. What was the exact proposal to unify
class and module? Without much thought/analysis, it looks like
either of these could be done to unify class and module:

1. Allow an instance of a module to be created: "new" should be
a "class" method of a module and work just like it does with a
class. I think this would allow a module to do everything a
class can do.

2. Allow a class to be included just like a module can. I
think this would allow a class to do what a module can.

Right now, if you wanted to make an instance of a module you'd
have to make a proxy class to do the dirty work. Currently,
doing it like this gives you the most flexibility because you
can mixin/inherit this class/module wherever and make instances
of it:

module Mod
# put your class/module code here
end

class ModClass
include Mod
end

x = ModClass.new

I don't see why the language shouldn't allow one to make an
instance of the Mod above rather than having to make an
instance of the proxy class ModClass.

. or why you can't include a class.


____________________________________________________
Start your day with Yahoo! - make it your home page
http://www.yahoo.com/r/hs


Daniel Brockman

unread,
Jul 29, 2005, 12:20:24 AM7/29/05
to
Yukihiro Matsumoto <ma...@ruby-lang.org> writes:

>>> It is much simpler and easier to use than

>>> multiple inheritance.
>>
>> This is where our minds go apart. Is it because unifying
>> classes and modules would *enable* you to do weird things
>> like inheriting from both Array and Hash? I honestly
>> don't think anyone ever tried to do that, and I don't
>> think anyone would expect it to work in a useful manner.
>> Do you?
>
> If it is not impossible, the language should define the
> behavior for it. If it is possible to inherit from Array
> and Hash, _I_ have to do something.

Just do basically what you'd do if they were modules.

> Unifying them gives me too heavy burden.

The burden is not on you to make every string of valid Ruby
code do something useful.

Okay, wait a minute... I think I'm starting to see the real
problem here. I'm not very familiar with Ruby's internals,
but I know arrays and hashes are special fundamental types.

If you do "class Foo < Array", will instances of Foo be
ordinary objects or will they be T_ARRAYs?

>>> Why people want "real" multiple inheritance by unifying
>>> classes and modules, when Ruby's mixin inheritance works


>>> quite well?
>>
>> Because it would do the same thing, only in a
>> simpler way. I hesitate to invoke Occam's Razor, but
>> it's definitely about orthogonality of concepts.
>
> Pardon me? You feel multiple inheritance simpler?
>
> It has fewer restriction, more general, but not simpler,
> both in concept and implementation.

I think it is simpler in concept. I believed it was no more
or less simple in implementation until I considered the
issue I mentioned above.

> Perhaps we are using the term "simple" in
> different manner.

That would certainly explain a few things. All else being
equal, I consider "fewer concepts" to imply "more simple".
(All else would not be equal in this case, but in my mind
very little would change.)

> When they would do almost the same thing, and when mixin
> inheritance is much simpler to understand (for me at
> least),

Ah, this may be the heart of the controversy. Some people
consider mixin inheritance much simpler to understand,
while others consider it just unnecessarily complicated.

Maybe it *is* just a matter of taste.

> far easier to implement,

I can't comment on that. Hats off to you. :-)

> why should I implement multiple inheritance?

From your point of view, there seems to be no reason to.
On the contrary, it seems positively undesirable.

Thank you for taking the time to discuss this matter.

--
Daniel Brockman <dan...@brockman.se>

Daniel Brockman

unread,
Jul 29, 2005, 12:30:48 AM7/29/05
to
"Trans" <tran...@gmail.com> writes:

> matz wrote:
>
>> When they would do almost the same thing, and when mixin
>> inheritance is much simpler to understand (for me at
>> least), far easier to implement, why should I implement
>> multiple inheritance?
>
> If I may, I don't think you should implement MI.
> Yet neither do I think a differentiation between class and
> module is neccessary. I think this is the common point of
> view of those who think calss and module should be merged,
> but that view continuly gets lost in the MI talk. I'm all
> for Ruby's SI with mixins, but the effects ought to be in
> the usage, not in the name.

I think that's a very insightful way of putting it, and I
agree completely. Except I still do not understand what the
term "multiple inheritance" means in Ruby circles.

Your examples make a good case for the unification, too.

--
Daniel Brockman <dan...@brockman.se>

Yukihiro Matsumoto

unread,
Jul 29, 2005, 12:31:18 AM7/29/05
to
Hi,

In message "Re: What's so special about operators, built-in classes and modules?"

on Fri, 29 Jul 2005 13:20:24 +0900, Daniel Brockman <dan...@brockman.se> writes:

|Okay, wait a minute... I think I'm starting to see the real
|problem here. I'm not very familiar with Ruby's internals,
|but I know arrays and hashes are special fundamental types.
|
|If you do "class Foo < Array", will instances of Foo be
|ordinary objects or will they be T_ARRAYs?

They will be T_ARRAY objects.

matz.


Yukihiro Matsumoto

unread,
Jul 29, 2005, 12:54:17 AM7/29/05
to
Hi,

In message "Re: What's so special about operators, built-in classes and modules?"

on Fri, 29 Jul 2005 11:00:47 +0900, Daniel Brockman <dan...@brockman.se> writes:

|Mathieu Bouchard replied[1],
|
|>>> module A; end
|>>> module B; include A; end
|>>> module C; include A; end
|>>> class D; include C,B; end
|>>>
|>>> This is a diamond inheritance pattern.
|
|but you never replied back to him.
|
|I'd appreciate it if someone could clarify once and for all
|how the diamond inheritance problem doesn't exist in Ruby.

The relationship figure should be the following:

Object
|
A-C | B-A
\|/
D

I want to mixin behave more like traits. The precedence should be
[D, C, A, B, A, Object] in the future.

This is a drawback I mentioned in [ruby-talk:149778]:
>I know there's some drawbacks in the current implementation of Ruby's
>mixin inheritance, when a module is included repeatedly. I am willing
>to fix it. I'm seeking the best way to fix.

Since repeated mixin inclusion is pretty rare case, this problem have
been there for long time.

matz.


Daniel Brockman

unread,
Jul 29, 2005, 1:57:38 AM7/29/05
to
Jim Weirich <j...@weirichhouse.org> writes:

[Nice treatise on repeated inheritance snipped.]

Thanks for writing that up, it was a good read.

Unfortunately, while it did answer my question as stated,
it did not answer the question I *meant* to ask. :-)

> So, in summary, why is diamond (repeated) inheritance not
> a problem in Ruby modules?
>
> Because the memory layout issues that force multiple
> copies of a base class just don't exist in Ruby.

So you agree that the issue of diamond inheritance is
completely unrelated to the class/module distinction.

Is that correct?

I want to know because the diamond bogeyman is constantly
brought up when talking about the feasibility of unifying
modules and classes. (When asked to be more specific, the
person who brought it up will generally become either silent
or seemingly very confused.)

--
Daniel Brockman <dan...@brockman.se>

Daniel Brockman

unread,
Jul 29, 2005, 2:18:25 AM7/29/05
to
Eric Mahurin <eric_m...@yahoo.com> writes:

> Daniel,
>
> I haven't really followed this VERY long thread completely,

Who could blame you, really? :-)

> but I'd thought I'd jump in. What was the exact proposal
> to unify class and module?

Quoting Mathieu Bouchard's proposal[1] from two years ago,

1. Module == Class returns true, and so no longer
Module < Class returns true. Therefore,
Module#include would work with Class arguments and
class A < x would work for any Module x.

2a. Class#new is moved to Object.new. [Mathieu
accidentally swapped the hash and dot in his
original message.] A Class that does not have
Object in its ancestor list does not inherit from
Object.new and is thus uninstantiable.

OR

2b. Class.new stays where it is. Former Modules thus
become instantiable (though not necessarily
meaningfully).

I would go for 2a, because I don't see any reason to allow
former modules to be instantiated at the expense of not
being able to have a non-instantiable class/module.

3. The "class" and "module" keywords would become
equivalent. Maybe the difference would be that the
default for "class" is to inherit from Object, and
the default for "module" is to not inherit at all.

4. A Class can inherit from another Class.
The inheriting Class may have Object twice in its
ancestors, but Ruby's ancestor lookup would eliminate
duplicates in the same way that non-Class Modules are
when they are duplicately #included according to the
rules of the current system.

Mathieu then went on to list the difficulties he could see
with implementing this, only one of which was technical:

If Class === B and Class === A and B < A, then also
(class << B ; self ; end) < (class << A ; self ; end).
This does not occur if A is a non-Class Module, nor in
any other case.

A Class inheriting from another cause the corresponding
metaclasses to inherit from each other. This has an
effect on "class methods". This thing currently does
not happen in non-Class Modules. I wonder whether there
are adverse consequences of making it happen in
non-Class Modules. I have not fully examined yet.
This may be the only outstanding technical issue.

This is the issue that I and Ara have been discussing
recently, and I have been trying to understand whether there
was good reason for the difference in the first place.

--
Daniel Brockman <dan...@brockman.se>

[1] <http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-core/1442>

gabriele renzi

unread,
Jul 29, 2005, 5:02:51 AM7/29/05
to
Daniel Brockman ha scritto:


>
>>Perhaps we are using the term "simple" in
>>different manner.
>
>
> That would certainly explain a few things. All else being
> equal, I consider "fewer concepts" to imply "more simple".
> (All else would not be equal in this case, but in my mind
> very little would change.)

The point is that once you introduce MI (which is a simpler concept than
single-class-inheritance-with-modules-mixed-in) you bring a lot of new
concepts with it, i.e.

- repeated inheritance
- diamond inheritance
- more complex semantics for "super", both in his class usage and for
builtin overriding
- how should the mwethod resolution work? Should it have a fixed order
be user-updateable ? In one case it would be less useful, in the other
you would need to add another concept
- ..the same for class functions, maybe
- maybe we could add a way to use a rename+select thing like in Eiffel,
but would it play nicely with ruby's dynamic nature?

and probably some more things.
Mind you, I agree that in a theoretical non-ruby language MI would be
nice ;)

Jim Weirich

unread,
Jul 29, 2005, 6:51:55 AM7/29/05
to
On Friday 29 July 2005 12:54 am, Yukihiro Matsumoto wrote:
> I want to mixin behave more like traits.  The precedence should be
> [D, C, A, B, A, Object] in the future.
>
> This is a drawback I mentioned in [ruby-talk:149778]:
> >I know there's some drawbacks in the current implementation of Ruby's
> >mixin inheritance, when a module is included repeatedly.  I am willing
> >to fix it.  I'm seeking the best way to fix.
>
> Since repeated mixin inclusion is pretty rare case, this problem have
> been there for long time.

In version 2.3, Python changed the way it resolves methods lookups. Its new
way of looking up methods preserves something called monotonic lookup, ie if
module A precedes module B in the method lookup of class C, then A always
procedes B in lookups of things derived from C. (See
http://www.python.org/2.3/mro.html)

Is the lack of monotonic lookup the problem you are refering to above?

Jim Weirich

unread,
Jul 29, 2005, 6:56:03 AM7/29/05
to
On Friday 29 July 2005 01:57 am, Daniel Brockman wrote:
> So you agree that the issue of diamond inheritance is
> completely unrelated to the class/module distinction.
>
> Is that correct?

Yes, at least from a non-implementors point of view.

As Matz has pointed out in another message, there are things going on at an
implementation level that we don't necessarily see as regular users of Ruby
that make repeated inheritance tricky (e.g. that fact that an array object is
a T_ARRAY).

Daniel Brockman

unread,
Jul 29, 2005, 7:13:36 AM7/29/05
to
gabriele renzi <surren...@remove-yahoo.it> writes:

>>> Perhaps we are using the term "simple" in
>>> different manner.
>>
>> That would certainly explain a few things. All else being
>> equal, I consider "fewer concepts" to imply "more simple".
>> (All else would not be equal in this case, but in my mind
>> very little would change.)
>
> The point is that once you introduce MI

Once we introduce *unified* MI.

Face it: We already have MI, in one form or another.

What about calling it "multiclass inheritance", or MCI?

(By the way, Matz has since given a good, tangible reason
for not unifying: It's not clear what should happen if you
inherit from both Array and Hash, which are special types.)

> (which is a simpler concept than single-class-inheritance-
> with-modules-mixed-in) you bring a lot of new concepts
> with it, i.e.
>
> - repeated inheritance

No. [ruby-talk:149932]

> - diamond inheritance

No. [ruby-talk:149845]

> - more complex semantics for "super",

Super would still call the next method.

> both in his class usage

What is "his class usage"?

> and for builtin overriding

What is "builtin overriding"?

> - how should the mwethod resolution work?

As it does now, by linearizing depth-first.

> Should it have a fixed order

Yes, for some values of "fixed".

> be user-updateable?

Yes, for some values of "user-updateable".

> In one case it would be less useful, in the other you
> would need to add another concept

No, we don't need any new concepts.

> - ..the same for class functions, maybe

Yes, as discussed elsewhere in this thread, singleton
methods on modules are a problem, but a solution does not
have to introduce any new concepts. For example, one
possible solution is to make modules behave in this regard
as classes currently do.

> - maybe we could add a way to use a rename+select thing
> like in Eiffel,

That sounds cool, and I'll probably be all for it.
However, it is irrelevant to this discussion.

> but would it play nicely with ruby's dynamic nature?

Why not?

> and probably some more things.

Probably not.

> Mind you, I agree that in a theoretical non-ruby language
> MI would be nice ;)

Are you thinking of any particular "theoretical
non-ruby language"?

gabriele renzi

unread,
Jul 29, 2005, 9:02:17 AM7/29/05
to
Daniel Brockman ha scritto:

> gabriele renzi <surren...@remove-yahoo.it> writes:
>
>
>>>>Perhaps we are using the term "simple" in
>>>>different manner.
>>>
>>>That would certainly explain a few things. All else being
>>>equal, I consider "fewer concepts" to imply "more simple".
>>>(All else would not be equal in this case, but in my mind
>>>very little would change.)
>>
>>The point is that once you introduce MI
>
>
> Once we introduce *unified* MI.
>
> Face it: We already have MI, in one form or another.
>
> What about calling it "multiclass inheritance", or MCI?

ok, I won't mind about it :)


>>(which is a simpler concept than single-class-inheritance-
>>with-modules-mixed-in) you bring a lot of new concepts
>>with it, i.e.
>>
>>- repeated inheritance
>
>
> No. [ruby-talk:149932]

sorry, I disagree with Jim, even if that was an insightful reading.


Compare:
# yes I know it is a bad use case for inheritance,
# since you'd use a PersonData class
class Person
def initialize(name, addr)
@name,@addr = name, addr
end
end

class SuperHero < Person
def initialize(name)
super pseudonomize(name), nil
end
end

class Reporter < Person
def initialize(name, addr, newspaper)
super(name, addr)
@newspaper=newspaper
end
end

class KentPerson < SuperHero, Reporter
def initalize
super(Reporter, name, addr, 'globe')
super(SuperHero, 'superman guy')
end

what would @addr be?

>
>>- diamond inheritance
>
>
> No. [ruby-talk:149845]

sorry, I'm dumb and I don't understand.
What are you "no"-ing to? that message *is* about diamond inheritance.
thus the concept have to be explained and introduced.


>
>>- more complex semantics for "super",
>
>
> Super would still call the next method.

sure, which one ? the one in the first superclass or the second?
What about choice? Think of super in python

>
>>both in his class usage
>
>
> What is "his class usage"?

class Foo
def to_s
..
end
end

class Baz < Foo, String,
def to_s
super # which class gets called?
end
end


>
>>and for builtin overriding
>
>
> What is "builtin overriding"?

def p(x)
super 'overriden: '+x.inspect
end

>
>
>>- how should the mwethod resolution work?
>
>
> As it does now, by linearizing depth-first.

ok


>
>> Should it have a fixed order
>
>
> Yes, for some values of "fixed".
>
>
>> be user-updateable?
>
>
> Yes, for some values of "user-updateable".

sorry, I don't understand what you mean.
I think as "user-updateable" the case of having an @ancestor variable or
something like that. Fixed would just leave an ancetors as it is now.
Ho would you merge this?

>
>> In one case it would be less useful, in the other you
>> would need to add another concept
>
>
> No, we don't need any new concepts.

sorry, we already introduced a lot, imho. I guess we can agree to disagree.

>
>>- ..the same for class functions, maybe
>
>
> Yes, as discussed elsewhere in this thread, singleton
> methods on modules are a problem, but a solution does not
> have to introduce any new concepts. For example, one
> possible solution is to make modules behave in this regard
> as classes currently do.

I did'nt read this yet


>
>>- maybe we could add a way to use a rename+select thing
>> like in Eiffel,
>
>
> That sounds cool, and I'll probably be all for it.
> However, it is irrelevant to this discussion.

it is relevant as a new concept

>
>> but would it play nicely with ruby's dynamic nature?
>
>
> Why not?
>

mh.. renaming and sdelection is done at compile time as some kind of
"syntactic" thing, while in ruby we have definition as a runtime event.
I am frightened it may mess up.

>
>>and probably some more things.
>
>
> Probably not.
>
>
>>Mind you, I agree that in a theoretical non-ruby language
>>MI would be nice ;)
>
>
> Are you thinking of any particular "theoretical
> non-ruby language"?


nope. Io, maybe?

gabriele renzi

unread,
Jul 29, 2005, 9:08:24 AM7/29/05
to
gabriele renzi ha scritto:

> Daniel Brockman ha scritto:
>
>> gabriele renzi <surren...@remove-yahoo.it> writes:
>>
>>
>>>>> Perhaps we are using the term "simple" in
>>>>> different manner.
>>>>
>>>>
>>>> That would certainly explain a few things. All else being
>>>> equal, I consider "fewer concepts" to imply "more simple".
>>>> (All else would not be equal in this case, but in my mind
>>>> very little would change.)
>>>
>>>
>>> The point is that once you introduce MI
>>
>>
>>
>> Once we introduce *unified* MI.
>>
>> Face it: We already have MI, in one form or another.
>>
>> What about calling it "multiclass inheritance", or MCI?
>
>
> ok, I won't mind about it :)
>
>
>>> (which is a simpler concept than single-class-inheritance-
>>> with-modules-mixed-in) you bring a lot of new concepts
>>> with it, i.e.
>>>
>>> - repeated inheritance
>>
>>
>>
>> No. [ruby-talk:149932]
>
>
> sorry, I disagree with Jim, even if that was an insightful reading.

mh, wait I actually agree with jim that the actual CIWM does not avoid
completely this, but since you almost never write an initialize in a
module, and initialization is usually done there, since they're not
instantiatable, you don't need to face it as you would with classes,
since all classes have an initialize method.

Jim Weirich

unread,
Jul 29, 2005, 12:14:51 PM7/29/05
to

gabriele renzi said:
>> sorry, I disagree with Jim, even if that was an insightful reading.
>
> mh, wait I actually agree with jim that the actual CIWM does not avoid
> completely this, but since you almost never write an initialize in a
> module, and initialization is usually done there, since they're not
> instantiatable, you don't need to face it as you would with classes,
> since all classes have an initialize method.

Agreed.

Adam P. Jenkins

unread,
Jul 29, 2005, 5:14:01 PM7/29/05
to
Ara.T.Howard wrote:
> On Fri, 29 Jul 2005, Jim Weirich wrote:
>
>>> did you run this? this is most defintely __not__ the diamond problem
>>> - it
>>> is strictly a tree:
>>
>>
>>> From my point of view, it looks like a diamond include structure, i.e.
>>
>>
>> A
>> / \
>> B C
>> \ /
>> D
>>
>> Ruby does linearizes the method resolution order to D,C,B,A.
>
>
> right - we are saying the same thing - the diamond is reduced to a line
> - ergo
> no 'diamond' problem - it's avoided by requiring the programmer to order
> the
> line via 'include'.

By your logic, C++ and Python don't have the diamond problem either.
Both of those languages have well defined ways in which the method to
call is chosen, which have to do with the order in which the programmer
writes things. So from the compiler's point of view, there is never a
diamond problem, unless you had a language specification which didn't
define any rules for resolving the issue. The "diamond problem" is a
problem for humans, who may not always remember, or take into account,
the language's rules for choosing which method to call, so in that sense
Ruby's module include feature introduces exactly the same "diamond
problem" that multiple inheritence introduces into other languages.

Adam

Ara.T.Howard

unread,
Jul 29, 2005, 5:57:05 PM7/29/05
to

all true - but only for methods. the thing with inheritence is that state
(instance vars) also get inherited. with ruby writing

module M
def foobar
@foobar || = 42
end
end
module N
def foobar_foobar
@foobar || = 42
[@foobar, @foobar]
end
end
class A
include M
include N
end
class B
include M
include N
end

p A::new.foobar
p A::new.foobar_foobar
p B::new.foobar
p B::new.foobar_foobar

results in the A object and the B object having exactly one copy of @foobar in
them. if A and B inherited from, rather than mixed-in, M and N then the
'problem' is what to do with @foobar. ruby could, as c++ has done, add
something like a virtual keyword to allow the programmer to prevent having two
copies of @foobar, it could merge them, who knows. it would, however, be a
'problem' that we don't currently have - and that c++ and python do. another
issue is

class A
def foobar
42
end
end

class B
def foobar
'forty-two'
end
end

class C < A, B
def foobar
super # what does this do?
end
end

class D < C
def foobar
super
end
def initialize
class << self
def foobar
super # what does this do?
end
end
end
end

module M
def foobar
super
end
end

class E < D
extend M # what does this do when E#foobar is called?
end

it's not that these things are not solvable - just that they are hard. c--
solved some of the above by having a complex syntax for calling specific
'supers'. it took compiler writers __years__ to follow the c++ spec and
multiple inheritence was one of the more difficult things to do (apparently).
the handling of it is non-trivial for the compiler writer.

so now we do have a simple kind of 'diamond inheritence' but no 'diamond
problem' in the ruby runtime since the ordering of module inclusion, as
written by the programmer, makes totally unambiguous the search path of method
calls.

cheers.

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| My religion is very simple. My religion is kindness.
| --Tenzin Gyatso
===============================================================================

Jim Weirich

unread,
Jul 30, 2005, 12:11:54 AM7/30/05
to
On Friday 29 July 2005 06:01 pm, Ara.T.Howard wrote:
> if A and B inherited from, rather than mixed-in, M and N then the
> 'problem' is what to do with @foobar.  ruby could, as c++ has done,

I see no reason why they couldn't be merged ... in fact, I have a hard time
imagining not treating them exactly as module inclusion does today.

> it would, however,
> be a 'problem' that we don't currently have - and that c++ and python do.

Python keeps only one copy, just as Ruby currently does with module inclusion.

Adam P. Jenkins

unread,
Aug 1, 2005, 2:02:53 PM8/1/05
to
Ara.T.Howard wrote:
> On Sat, 30 Jul 2005, Adam P. Jenkins wrote:
>> By your logic, C++ and Python don't have the diamond problem either.
>> Both of
>> those languages have well defined ways in which the method to call is
>> chosen, which have to do with the order in which the programmer writes
>> things. So from the compiler's point of view, there is never a diamond
>> problem, unless you had a language specification which didn't define any
>> rules for resolving the issue. The "diamond problem" is a problem for
>> humans, who may not always remember, or take into account, the language's
>> rules for choosing which method to call, so in that sense Ruby's module
>> include feature introduces exactly the same "diamond problem" that
>> multiple
>> inheritence introduces into other languages.
>
>
> all true - but only for methods. the thing with inheritence is that state
> (instance vars) also get inherited.

<snipped explanation showing that state can't be multiply inherited in
Ruby.>

> so now we do have a simple kind of 'diamond inheritence' but no
> 'diamond problem' in the ruby runtime since the ordering of module
> inclusion, as written by the programmer, makes totally unambiguous
> the search path of method calls.

But the fact is that the C++ standard explicitly and unambiguously
defines the behavior for multiply inherited state as well. So, I still
say that, if you maintain that the fact that Ruby has a well defined way
of resolving which method to call when multiple modules include the same
method name means that Ruby doesn't have the diamond problem, then the
same logic should apply to C++. Since C++ has a well defined way of
resolving which instance variable gets accessed at any point in the
code, there is no diamond problem.

Personally I don't think the "diamond problem" shouldn't be called a
problem just because there's a solution. Multiple inheritance
introduces the possibility that members with the same name can be
inherited multiple times at the same level in the inheritance tree.
This is a problem that must be resolved, and it is resolved in all the
MI languages I've used. Nevertheless, even though the compiler knows
what to do, the programmer may still get unexpected behavior if they
multiply inherit (or multiply include in Ruby), without being aware that
they are including multiple versions of the same member. Another way of
putting it is, just because the behavior is unambiguous to the compiler,
that doesn't mean it always seems unambiguous to the programmer. In
that regard, I do agree that by disallowing multiply-inherited state,
Ruby makes its behavior easier for humans to keep straight in their
heads. But I don't agree with the claim in the Pickaxe book that Ruby's
module include feature "provides a controlled multiple-inheritance-like
capability with none of the drawbacks."

Adam

Ben Giddings

unread,
Aug 8, 2005, 6:32:50 PM8/8/05
to
On Jul 27, 2005, at 12:07, Ara.T.Howard wrote:
> this is a similar 'argument':
>
> in c most people think that a definition like
>
> int foobar (const char * string);
>
> will prevent people from modifiying string. it won't. for that
> one needs
>
> int foobar (const char * const string);
>
> why not unify them?
>
> the answer is obvious: because they are differnet. a focus on
> clarifying
> doccumentation might be wiser in this case. and, in the end,
> certain people
> are simply going to have to be told to rtfm - not everything can be
> intuitive
> AND powerful.

Actually, the first example will prevent people from modifying the
string, at least directly. Adding the second const only prevents
them from reassigning the "string" variable within the function.

The biggest problem here is that in C strings don't exist. People go
to great lengths to pretend that they do, but really, they don't.
There are only arrays of characters terminated by a null character.
If people would quit believing that strings actually exist, then the
problems with strings and C would go away.

What makes the problem worse is that C makes it really easy to
believe that strings exist. Having constructs like "Hello World!\n"
makes people think that there is such a thing as a string, but the
compiler sees that as being identical to {'H', 'e', 'l', 'l', 'o', '
', 'W', 'o', 'r', 'l', 'd', '!', '\n', '\0'}.

Now you could argue that strings actually *do* exist, and that they
*are* arrays of characters terminated by a null. I don't buy it
though. Why not? Because *anything* can be a string of characters
terminated by a null. C may be statically typed, but try declaring
an array of characters and then calling strlen(the_array). It may
give you a length, or maybe a segfault, but it will never say "hey!
that's not a string!"

Aside from the issue of C strings, I'd say the way const is used in
functions is b0rken in C. Take int foo(const int bar); Since bar is
passed by value, any modifications of it in the body of the function
are only local to the function. In my experience good C coders treat
every parameter passed by value as "const", otherwise they lose a
record of what parameters the function was supplied. Because of
this, "const" is only really useful when applied to pointers. And
the syntax for that is really confusing -- generally the syntax for
pointers is really confusing in C as a general rule. The concept of
a pointer is pretty simple -- it's an address in memory, the only
thing that makes it difficult is the syntax.

In this bit of code, you can change the variable a, which is a
pointer, making it point at something else, but you can't change the
value it points at. As for b, you can change the value it points at,
but you can't change the variable itself.

int bar(const int *a, int *const b, const int c)
{
int d, e;
//*a = 3;
*b = 4;
a = &d;
//b = &e;
//c = 5;
}

The "const char* string" works the same way, preventing you from
modifying the contents of the string, but letting you reassign the
variable. The way to read it (I believe) is "if you dereference
'string' you will get a constant character".

Anyhow, bringing this back to Ruby...

I think Modules and Classes should be separate, but I think there's a
lot of confusion there.

Classes are pretty straightforward, but modules are not. I'd say
most of the confusion comes from the fact that modules can either be
groups of functions that are mixed in to other things, or they can be
namespaces. That dual use gets confusing. Oh, and it's also
confusing that a Class is a Module in the inheritance tree.

I agree that it's confusing that including a module doesn't hide
functions that a class defines on its own. IMHO it isn't clear that
"include FooModule" is similar to inheritance. It looks like it's
similar to "attr_accessor", not like class Foo < Bar.

Adding documentation would help a bit with this issue, but it doesn't
seem like the ideal approach to me. Instead of documenting a
confusing issue, why not understand why it's confusing and fix it?

I'd suggest that for one thing, modules-as-namespaces should
disappear, there should simply be a "namespace" keyword so "Math::PI"
is in the Math namespace, not the Math module. Then, I'd say "mixin"
instead of "module". Finally to address the issue of it not
overriding methods that already exist, maybe a second parameter to
"include" named "override" that defaults to false? Sure, that could
break things when you mix something in that clobbers a "helper
method", but just having that option there makes people realize that
it doesn't always override things.

As for multiple inheritance vs. single inheritance, I think the
problem isn't a technical one, it's a human one. As Adam P Jenkins
pointed out:

By your logic, C++ and Python don't have the diamond problem
either. Both
of those languages have well defined ways in which the method to
call is
chosen, which have to do with the order in which the programmer
writes things.

So the question becomes "What is going to provide the most
flexibility with the least confusion?" I think that rules out
multiple inheritance. Ruby is a really flexible language. Even
without resorting to "eval" you can do some pretty astounding
things. But in general the approach seems to be "unless you're
trying to do something tricky, things generally behave as they
should". I would say that having multiple inheritance adds a lot of
potential for confusion without a lot of benefit. Crafty programmers
can get all(?) the benefits of MI from Ruby today, as long as they're
willing to be sneaky about it. Less crafty programmers don't have to
worry about the diamond problem. Doesn't that seem like the way
things should be?

Ben

0 new messages