Why the lack of mixing-in support for Class methods?


#81

On 6/12/06, removed_email_address@domain.invalid removed_email_address@domain.invalid wrote:

what did you think about my solution matz? it’s solves the issue cleanly and
is leverages existing practices. here it is again:

I for one like it - pragmatic and straightforward. However, I’m not
sure why you want the InstanceMethods module (unless it’s to be
explicit).

Regards,
Sean


#82

Logan C. wrote:

  mod.extend(class << self; self; end)
end

end

i.e. extend the receiver with the methods and constants of the
singleton class. It sure would make this whole problem a lot easier to
solve, and avoid those pesky hacks we’re all but fond of.

Then you have multiple inheritance.

Yes.


#83

Hi,

In message “Re: Why the lack of mixing-in support for Class methods?”
on Mon, 12 Jun 2006 13:37:25 +0900, removed_email_address@domain.invalid writes:

|I guess what I don’t understand is this: If I can manully separate the
|“class-level” into it’s own module and resuse that, why can’t I just
|reusue the class-level to begin with?

Because it makes thing more complex, I guess. Mere #include should
not inherit class/module-level methods, since there are cases like
Math module. So we need to prepare two different method for module
inclusion instead of one, if we reuse class-level.

						matz.

#84

On Tue, 13 Jun 2006, Sean O’Halpin wrote:

Sean
module M
include Inheritable
module ClassMethods
def foo() ‘foo’ end
end
module InstanceMethods
def bar() ‘bar’ end
end
end

class A
include M # here we get everything due to overridden self.include
end

class B
include M::InstanceMethods # here we cherry pick
end

class C
extend M::ClassMethods # also cherry picking
end

if, instead we were to do

module M
include Inheritable
module ClassMethods
def foo() ‘foo’ end
end

 def bar() 'bar' end

end

then this also works with Inheritable

class A
include M # here we get everything due to overridden self.include
end

since the overridden self.include calls super, but you lose the ability
to
cherry pick the instance methods. Note that the InstanceMethods modules
is
totally optional and only makes sense if you plan on cherry picking
later -
which i’ve actually done three for four times every. in pratice my own
inheritable.rb looks like this:

module Inheritable
Inherit = lambda do |this, other|
cm = this.const_get ‘ClassMethods’ rescue nil
im = this.const_get ‘InstanceMethods’ rescue nil
m = this.const_get ‘Methods’ rescue nil
other.extend cm if cm
other.extend m if m
other.module_eval{
include im if im
include m if m
extend RecursiveInherit
}
end

 module RecursiveInherit
   def included other
     Inherit[self, other]
     super
   end
 end

 extend RecursiveInherit

end

so the rules are

ClassMethods => class methods only
InstanceMethods => instance methods only
Methods => methods that can be called at class or instance
level
(none) => ‘normal’ instance methods, no cherry picking

this covers all the bases and make sense even to newbies reading the
code.
90% of all cases will only use ClassMethods, however.

cheers.

-a


#85

Gregory S. wrote:

On Mon, Jun 12, 2006 at 07:19:10PM +0900, Daniel S. wrote:
} class Module
} def meta_module(&block)
} @meta_module ||= Module.new
} @meta_module.module_eval(&block)
} extend(@meta_module)

Why should the module extend the meta_module?

Because I’d like the meta-module methods to act as module methods – if
you don’t like that, remove that line.

it out:

% irb
irb(main):001:0> Object.kind_of? Module
=> true

Or `instance_of? Module’

Again, I haven’t had time to fully test this implementation – please
focus on the interface.

Cheers,
Daniel


#86

On Jun 12, 2006, at 12:04 PM, Daniel S. wrote:

end

end

i.e. extend the receiver with the methods and constants of the
singleton class. It sure would make this whole problem a lot
easier to solve, and avoid those pesky hacks we’re all but fond of.
Then you have multiple inheritance.

Yes.

That’s why it’s not possible. matz. has strong feelings about MI.


#87

Daniel S. wrote:

Logan C. wrote:

Then you have multiple inheritance.

Yes.

Not really. Mulitple Inheritance provides orthogonal heirarchies.
Ruby’s is strictly linear. If what you say were true then Ruby would
already be MI since modules can be used to add behavior to both class
and instance levels, and readily associated together as well, as Ara’s
example clearly demonstrates. To think this consititutes MI and thus
making specialized restrictions of code separation to repress it, only
serves to complixify the situation, not the other way around. It’s like
trying to prevent someone from getting to their destinatin by not
allowing them to turn right --they’ll still get there, they’ll just
turn left three times.

T.


#88

Logan C. wrote:

class Module
Yes.

That’s why it’s not possible. matz. has strong feelings about MI.

I’m not saying we should add it to core – but I don’t understand why we
shouldn’t allow people to do it themselves.

If it was possible to include classes into modules/classes, it would
still just be the instance methods and constants of the included class
– so it isn’t full inheritance. If the coder overwrites
Module#included, full inheritance can be achieved. I don’t think it
should be up to us whether or not we will allow people to do that.

I’m sorry if I don’t make much sense right now, I’m a bit drunk (sorry).

Cheers,
Daniel


#89

On Tue, 13 Jun 2006 removed_email_address@domain.invalid wrote:

and instance levels, and readily associated together as well, as Ara’s
example clearly demonstrates. To think this consititutes MI and thus
making specialized restrictions of code separation to repress it, only
serves to complixify the situation, not the other way around. It’s like
trying to prevent someone from getting to their destinatin by not
allowing them to turn right --they’ll still get there, they’ll just
turn left three times.

T.

in my mind it’s this that makes it not mi

 harp:~ > cat a.rb
 module A
   def foo() 'foo' end
 end
 module B
   def bar() 'bar' end
 end
 module C
   def bar() foo() end
 end

 class D
   include A
   include B
   include C
 end

 p D.new.foo


 harp:~ > ruby a.rb
 "foo"

now, if ruby was truely mi then i could write something (imagined) like

class D < (A, B, C)
end

p D.new.foo

and ruby would be free to print either ‘foo’ or ‘bar’. clearly it would
be
one or the other and a ruleset would exist to make it un-ambiguous, but
the
difference between ruby deciding and having built-in rules vs me
deciding and
have explicit call hierachies aranged manually is a rather large one.

so, to me, this is the crucial thing which prevents me from considering
ruby
to be a true mi lang. the cool thing, of course, is that it’s only a
few
lines of code to make is behave as if it was.

cheers.

-a


#90

I’ve read most of this thread and still am a little confused. I’m no
ruby
guru by any stretch of the imagination, but I use modules to house code
that
can be utilized in various classes. If I need class methods then I use
inheritance. IMO, this is simple and clean.

So far, there doesn’t seem to be a clean/simple way to have mixin
support
for class methods. Until that epiphany is reached, I would think it
would
be better to leave things as is.

I will give a novice suggestion:

Maybe instead of trying to work in this feature to modules, why not
introduce “ClassModule”? Or has this been said? This way it is clear
what
they use is and they can, in turn, have features specific to class
method
inheritance (if any are needed).

Therefore you could mix and match ClassModules with regular Modules.
Seems
pretty flexible to me. I have no idea how difficult this would be to
implement.


#91

This thread led me to write this:

= capsule.rb

== Copyright © 2006 Thomas S.

Ruby License

This module is free software. You may use, modify, and/or

redistribute this

software under the same terms as Ruby.

This program is distributed in the hope that it will be useful,

but WITHOUT

ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS

FOR A PARTICULAR PURPOSE.

== Authors & Contributors

* Thomas S.

Author:: Thomas S.

Copyright:: Copyright © 2005 Thomas S.

License:: Ruby License

= Capsule

A Capsule encapsulates reusable code and is an analog to the Module

class,

but rather than storing it’s own methods it simply stores modules.

These

modules are divided into two groups: extensions and inclusions. A

capsule

is reused via the Kernel#inherit method.

== Usage

module Foo

def foo ; “foo” ; end

end

module Bar

def bar ; “bar” ; end

end

C = Capsule.new do

extend Foo

include Bar

end

class X

inherit X

end

X.foo #=> “foo”

X.new.bar #=> “bar”

Use #[] as a shortcut for grouping one inclusion and one extension

together into

a new capsule.

C = Capsule[ Foo, Bar ]

class Capsule

attr_reader :extensions, :inclusions

def initialize( &template )
  @extensions = []
  @inclusions = []
  instance_eval &template if template
end

# Shortcut for creating an inclusion-extension pair capsule.

def self.[]( e, i )
  new << e < i
end

# Add modules to the inclusions group.

def include( *inclusions )
  @inclusions.concat inclusions
end

# Add modules to the extensions group.

def extend( *extensions )
  @extensions.concat extensions
end

# Add a module to the inclusions group.

def <( inclusion )
  @inclusions << inclusion
  self
end

# Add a module to the extensions group.

def <<( extension )
  @extensions << extension
  self
end

# Append this capsules features to a given base module or class.

def append_features( base )
  # use #instance_exec in Ruby 1.9+
  base.send( :extend,  *@extensions )
  base.send( :include, *@inclusions )
end

end

class Module

# Inherit behavior from other modules or capsules.

def inherit( *capsules )
  capsules.each do |c|
    c.append_features( self )
  end
end

end

No doubt it can be improved on, but it clearly ties together what Ruby
presently does and the behvior some of us would like to achieve.

T.


#92

On Jun 12, 2006, at 5:43 PM, Alder G. wrote:

already be MI since modules can be used to add behavior to both class

2b. It doesn’t seem to be widely considered “bad”, at least not by
resolved. But one of the major attractions of Ruby for me is the

I think a little context has been lost in this conversation, if I may
be permitted to go back and quote Mr. Schierbeck again:

I’m wondering why it’s not possible to #include a class into a
module/class – making the only difference between classes and
modules the ability to instantiate (#allocate). That way, you could
do something like this:

I do not see how straight up #include-ing a class would not be
multiple inheritance.

I’m was not talking including class methods, I’m talking about writing

class A
end

class B
end

class C
end

class D < A
include B
include C
end

IOW, erasing the distinction between classes and modules, which is
what Mr. Scheirbeck suggested, and what I took exception to.


#93

Logan C. wrote:

I think a little context has been lost in this conversation, if I may
be permitted to go back and quote Mr. Schierbeck again:

I’m wondering why it’s not possible to #include a class into a
module/class – making the only difference between classes and
modules the ability to instantiate (#allocate). That way, you could
do something like this:

I do not see how straight up #include-ing a class would not be
multiple inheritance.

Techincally it isn’t. Multiple inheritance can have iheritance
structures like so:

M N
\ /
C

Single inheritance (like Ruby) is strictly like this:

N
|
M
|
C

With Ruby, it doesn’t matter how many modules you include, it’s still
just a line of single inheritance. What’s unique about mixins is that
they allow us to slip “ancesotors” in between a class and it’s
superclass, thus augmenting behavior in a way similar to MI, but
wiithout many of the additional complexities of MI.

class D < A
include B
include C
end

IOW, erasing the distinction between classes and modules, which is
what Mr. Scheirbeck suggested, and what I took exception to.

Fair enough. But let me make clear that MI is not a wholly satisfactory
answer to Mr. Scheirbeck query. The answer is more subtle, a
distinction between module and class help promote two different forms
of behavioral inheritance, one primary (class) and the other secondary
(module). This is actually quite realistic. Think of a Car (class) with
optional feature like FullyLoaded (module). I don’t think anyone is
suggesting we remove that disticition, even if it is technically
debatable.

What was suggested though, is that the “class-level” of a module
might be more appropriately a “module-level”. Classes would still have
class-levels, but by giving modules their “own kind” in this role, the
difficulty of extending a class via a module’s “module-level” is easily
solved --a solution which is the hope of this thread. And such a
solution, I reitererate, does not in any way constitute MI.

T.


#94

On 6/12/06, removed_email_address@domain.invalid removed_email_address@domain.invalid wrote:

and instance levels, and readily associated together as well, as Ara’s

Exactly.

  1. Multiple module inclusion is not multiple inheritance. Even if you
    think it is - Ruby already has it. So unless you’re arguing for its
    removal - and nobody seems to want that - it’s a moot point.

  2. You may debate whether mixing-in class methods is a “bad” practice
    in some sense, and should therefore be discouraged - or at least not
    encouraged by adding elegant, clear and standard language support for
    it.

But:

2a. It can’t be that bad, since nobody is arguing that it should be
disallowed completely.

2b. It doesn’t seem to be widely considered “bad”, at least not by
several skilled Ruby hackers. Rails is highly regarded codebase, and
the ClassMethods hack is all over it. Rails is the only codebase I’m
(vaguely) familiar with, but posts in this thread indicate that other
good codebases use similar hacks to accomplish the same programming
strategy.

2c. Of course, one may argue that even if mixing-in of class methods
is done by many skilled Ruby hackers, and is a vital programming
strategy in many high quality Ruby programs, it is still “bad” in some
theoretical sense. This is a subjective argument that cannot be
resolved. But one of the major attractions of Ruby for me is the
TIMTOWDI philosophy. I did not think Ruby would try to discipline its
coders by inconveniencing them. Not that it would matter much - mixins
would continue to be used for classs method inclusion.

So in short, since it seems many people are mixin class methods, it
would be nice if it were handled by a standard - hopefully convenient,
elegant - language feature.


#95

Daniel S. wrote:

you suggesting we replace module objects’ singleton classes with such a
“module-level”, or would the singleton methods and constants be defined
in both?

You have to understand a little about how modules are tied into the
inhertiance chain. Modules are linked via virtual classes. (There are
some good diagrams of this in the Pickaxe, I believe it’s under
“Classes and Objects”). The idea is then to replace a module’s current
“metaclass” with a virtual class linking in a “metamodule”. Anything in
a module’s “class << self” then is defined in this metamodule instead.

What I thought would be great about allowing #include and #extend to
accept Class objects is that it would make it much easier for a module
(or, well, class) author to decide for himself whether or not he wishes
to have the module methods included as well.

Well, one can argue the merits for or against that. But it goes beyond
the need at hand. The division between module and class I think suits
Ruby. Allowing classes to be included outright, while not MI
underthehood, nonetheless appears as such on the surface b/c a class
than appears to be a child of a more than one class. But having modules
distinct, it can only be the child of one class and instead agumented
with extra modular behaviors.

 def self.foo

end

Test.foo #=> “a class method”
Test.new.bar #=> “an instance method”

I think module authors should be able to make that decision (as they do
now, with the hacks and all.)

While I’m for ‘mod.extend(class << AModule; self; end)’. I think the
use of #included is done nowadays b/c there is no other obvious way to
achieve the same thing. I think it’s unfortuate to have to depend on a
callback --and as things stand it goes beyond what a module user
generally expects from #include. So in that respect it’s not really a
good practice. What we really need is a good practice to replace this
callback pattern.

This would also allow module “users” to
opt-in on the module methods:

class Module
def inherit(*mods)
include *mods
mods.each{|mod| extend(class << mod; self; end)}
end
end

Yes, I think that’s a fair option. And IMHO would say that it’s the 2nd
best choice, behind the ability to specify ‘extensible’ and
‘uninheritable’ sections in ones modules. I still tend to think that
the the control is best left to a module itself. But short of that,
then this would be a good way. Of course, matz, doesn’t like the term
“inherit” bc/ it invokes ideas of MI, but any name will do.

(geez, it sure would be nice with a shorthand for singleton classes…)

I agree. I’ve been toying with “own” and “owner” lately myself.

T.


#96

removed_email_address@domain.invalid wrote:

What was suggested though, is that the “class-level” of a module
might be more appropriately a “module-level”. Classes would still have
class-levels, but by giving modules their “own kind” in this role, the
difficulty of extending a class via a module’s “module-level” is easily
solved --a solution which is the hope of this thread. And such a
solution, I reitererate, does not in any way constitute MI.

I agree with you throughout the post, and I do enjoy being called Mr.
Schierbeck (we seldom use such formalities where I am from,) but I’m
still not sure if we have the same idea about the “module-level”. Are
you suggesting we replace module objects’ singleton classes with such a
“module-level”, or would the singleton methods and constants be defined
in both?

What I thought would be great about allowing #include and #extend to
accept Class objects is that it would make it much easier for a module
(or, well, class) author to decide for himself whether or not he wishes
to have the module methods included as well. I agree with you that
multiple inheritance would mean a non-linear line of inheritance, and
that allowing Class objects to be included would not have such a
consequence. Basically, I think module authors should be able to write
this:

module MyModule
def self.included(mod)
mod.extend(class << self; self; end)
end

 def self.foo
   "a class method"
 end

 def bar
   "an instance method"
 end

end

class Test
include MyModule
end

Test.foo #=> “a class method”
Test.new.bar #=> “an instance method”

I think module authors should be able to make that decision (as they do
now, with the hacks and all.) This would also allow module “users” to
opt-in on the module methods:

class Module
def inherit(*mods)
include *mods
mods.each{|mod| extend(class << mod; self; end)}
end
end

(geez, it sure would be nice with a shorthand for singleton classes…)

Cheers,
Daniel


#97

removed_email_address@domain.invalid wrote:

… Modules are linked via virtual classes. (There are
some good diagrams of this in the Pickaxe, I believe it’s under
“Classes and Objects”). The idea is then to replace a module’s current
“metaclass” with a virtual class linking in a “metamodule”. Anything in
a module’s “class << self” then is defined in this metamodule instead.

All I wanted to know.

distinct, it can only be the child of one class and instead agumented
with extra modular behaviors.

So the functionality of modules repressed in order to preserved their
secondary nature? Why should we limit the power of modules just so that
we can say Ruby doesn’t allow MI?

I think it’s a plus if Ruby had the ability to be like an MI language,
just like it can appear to be functional.

Yes, I think that’s a fair option. And IMHO would say that it’s the 2nd
best choice, behind the ability to specify ‘extensible’ and
‘uninheritable’ sections in ones modules. I still tend to think that
the the control is best left to a module itself.

I think the use of sections is annoying – I’d much rather just define
in the module whether or not the module methods and constants should be
included, too. If you only want certain methods to be included, I think
the nested module approach is better.

(geez, it sure would be nice with a shorthand for singleton classes…)
I agree. I’ve been toying with “own” and “owner” lately myself.

I still like “metaclass” the best – it may not be the most precise, but
it flips off the tongue and keyboard. In the end, it’s up to matz; I
don’t don’t really care what name it’ll get, as long as it’s there.
`class << self; self; end’ is not the prettiest piece of code…

Daniel aka Mr. Schierbeck :slight_smile:


#98

Hi,

In message “Re: Why the lack of mixing-in support for Class methods?”
on Tue, 13 Jun 2006 22:35:14 +0900, removed_email_address@domain.invalid writes:

|> you suggesting we replace module objects’ singleton classes with such a
|> “module-level”, or would the singleton methods and constants be defined
|> in both?
|
|You have to understand a little about how modules are tied into the
|inhertiance chain. Modules are linked via virtual classes. (There are
|some good diagrams of this in the Pickaxe, I believe it’s under
|“Classes and Objects”). The idea is then to replace a module’s current
|“metaclass” with a virtual class linking in a “metamodule”. Anything in
|a module’s “class << self” then is defined in this metamodule instead.

I don’t think I understand you. Do you want to allow #include to
include classes? Without making it MI? Hmm.

						matz.

#99

On Jun 13, 2006, at 10:38 AM, Yukihiro M. wrote:

I don’t think I understand you. Do you want to allow #include to
include classes? Without making it MI? Hmm.

It isn’t altogether obvious to me why a class passed to #include
couldn’t be interpreted as a module (since instances of Class are
instances of Module via inheritance). That is to say the superclass
ancestors a class should not be considered by #include but any
included modules should be as well as any directly defined instance
methods. To illustrate:

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

M.ancestors => [M]
A.ancestors => [A, Object, Kernel]
B.ancestors => [B, A, Object, Kernel]
C.ancestors => [C, M, A, Object, Kernel]
D.ancestors => [D, C, M, B, Object, Kernel]

In the last example, A isn’t an ancestor because the superclass
relationship is ignored by my fictitious ‘include’.

While I think this behavior could be well-defined, I’m not sure the
subtlety is worth it nor do I think it suggests any particular answer
to the question of how singleton methods should be handled by
#include or some companion method that has been discussed. On that
point I’m in Matz camp. I don’t see an inherent relationship between
the instance methods of a module and the singleton methods of the
module object. In particular situations I can see the relationship
but it isn’t always guaranteed to be there. Instance methods are the
raison d’etre of modules but singleton methods may exist for any
object whatsoever. I’m not sure why they (singleton methods) should
be considered by #include at all.

I’m not sure I understand why singleton methods are tucked away in a
pseudo-class object since none of the Class instance methods (new,
superclass, allocate) seem to be applicable. The container for
singleton methods seems much more like a module than a class to me.
There is a relationship between the singleton classes of related
parent/child classes but couldn’t that be modeled as module
inclusion? I’m probably missing some subtlety. I am often reminded
of the maze in Adventure (“You are in a maze of twisty little
passages, all alike”) when I think about this stuff.

Gary W.


#100

Yukihiro M. wrote:

I don’t think I understand you. Do you want to allow #include to
include classes? Without making it MI? Hmm.

No no. You’d still only be able to include modules. I’m thinking a
module’s “singleton class” could be a “singleton module”, so to speak,
instead. It’s a bit difficult to communicate b/c the terminology is
caught up in how it curently works. But it’s a lot less fancy than I
think it sounds. I’ll use a diagram to make it clearer. Lets say we
have this code.

class Foo
include Moo
end

foo = Foo.new

A basic diagram of that currently looks like this:

 object foo
    ||
    \/
 class foo'  -> class Foo -> (vclass Moo)
                    ||            //
                    \/        module Moo
                class Foo'        ||
                                  \/
                               class Moo'

I’m thinking that instead it could be like this.

 object foo
    ||
    \/
 class foo'  -> class Foo -> (vclass Moo)
                    ||            //
                    \/        module Moo
                class Foo'        ||
                                  \/
                             (vclass Moo')
                                  //
                              module Moo'

In this way the so-called “class-level” of a module is instead a
“module-level”. Essentially:

module Moo
class << self
self.class #=> Module
end
end

Which is why I earlier used “module << self”.

Of course, in the implmentation you might be able omit the vclass Moo’
altogether. I just conceived of it that way becuase it readly
“plugs-in” to the current design.

T.