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

(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" <Ara.T.Howard@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?

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

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

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. inheritence needs to be
addressed specifically for it to make sense.

(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”

like this

   .[0m~@~Xfoo.[0m~0~X .[0m~@~\bar.[0m~@~]

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

tough to see that :wink:

cheers.

-a

···

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

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

===============================================================================

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 :wink:

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

   Multiple inheritance - Wikipedia

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

cheers.

-a

···

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

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

===============================================================================

Ara.T.Howard wrote:

This message is in MIME format. The first part should be readable
text, while the remaining parts are likely unreadable without
MIME-aware tools.

^--- Why are you doing this?

> "Ara.T.Howard" <Ara.T.Howard@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

···

On Thu, 28 Jul 2005, Daniel Brockman wrote:

--
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);}

"Ara.T.Howard" <Ara.T.Howard@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 <daniel@brockman.se>

"Ara.T.Howard" <Ara.T.Howard@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

   Multiple inheritance - Wikipedia

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 <daniel@brockman.se>

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?

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 :wink:

   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. 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.

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

tons. just yesterday i was writing a parser. all the code is wrapped in a
module to protect namespaces. each line of the file i am parsing is a command
sent to a satelite. i have a factory which produced command objects of a
given type that's arranged like

   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

however, i actually use this class in another like

   class PayloadActivationMessage < AbstractMessage
     include Command
   end

and this would change the notion of calling 'super' if what you are suggesting
were true. eg - if 'some_method' were defined as a class method in
PayloadActivationMessage, AbstractMessage, and Command, then a definition like

   def PayloadActivationMessage::some_method
     super + 42
   end

would seem to call AbstractMessage::some_method (due to inheritence) but would
actually call Command::some_method if class methods were automatically pulled
in by 'include' statements. there are cases where you want this and that's
what 'append_features' is for - but to have this for the normal case would be
quite suprising for most applications i think. not to mention changing the
notion of super is, be definition, a very strong form on inheritence.

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.

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

Why do you say that?

well - because that's what you are suggesting!?

pine, mutt, or mail.

but even the web interface shows the problem:

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

look at the line with 'const char' on it.

cheers.

-a

···

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

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

===============================================================================

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.

Thank you for keeping up Ara --- I'm enjoying this
discussion. :slight_smile:

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

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 :wink:

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"?

···

On Thu, 28 Jul 2005, Daniel Brockman wrote:

--
Daniel Brockman <daniel@brockman.se>

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.

cheers.

-a

···

On Fri, 29 Jul 2005, Trans wrote:
--

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

===============================================================================