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

1 view
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