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

Hi

I'm confused as to why class methods aren't include'd by default along
with instance methods when mixing-in modules.

It obstructs the important orthoganility between modules and classes,
and - among other problems - thus undermines the position of mixins as
an alternative to class-based multiple inheritance.

In short, I can see a lot of poor consequence to that lack of support,
while on the other hand no good reason for it. Maybe someone would
care to elighten me?

(I'm aware of the various hacks for fudging such support, and in fact
use some of them in my code. But there are readability and
maintainability issues with those hacks for something that's supposed
to be a core feature).

···

--
-Alder

The main reason is because a different 'self' is involved, I would guess.
You can use extend to mixin class methods. Also, there's a nice idiom
for getting include to mixin both class and instance methods of a
module (though the class methods are actually in another sub-module):

module A
  def self.included receiver
    receiver.extend ClassMethods
  end

  module ClassMethods
    def foo
      "foo"
    end
  end
  def inst_method
    "instance method"
  end
end

class B
  include A
end

B.foo #=> "foo"
B.new.inst_method #=> "instance method"

···

On 6/7/06, Alder Green <alder.green@gmail.com> wrote:

Hi

I'm confused as to why class methods aren't include'd by default along
with instance methods when mixing-in modules.

It obstructs the important orthoganility between modules and classes,
and - among other problems - thus undermines the position of mixins as
an alternative to class-based multiple inheritance.

In short, I can see a lot of poor consequence to that lack of support,
while on the other hand no good reason for it. Maybe someone would
care to elighten me?

(I'm aware of the various hacks for fudging such support, and in fact
use some of them in my code. But there are readability and
maintainability issues with those hacks for something that's supposed
to be a core feature).

Hi --

Hi

I'm confused as to why class methods aren't include'd by default along
with instance methods when mixing-in modules.

It obstructs the important orthoganility between modules and classes,
and - among other problems - thus undermines the position of mixins as
an alternative to class-based multiple inheritance.

In short, I can see a lot of poor consequence to that lack of support,
while on the other hand no good reason for it. Maybe someone would
care to elighten me?

It's actually a fairly specialized case. In the general case, if a
module has a method of its own, there's no particular reason to think
that every class that mixes it in should also have that method.

For example:

   module Edible
     def self.definition
       "able to be eaten without ill effect"
     end
   end

   class Bread
     include Edible
   end

   class Bagel < Bread
   end

You don't really want Bread or Bagel reporting back their definitions
as being the same as Edible's definition. You can arrange for that to
happen quite easily (see Phil's answer) if you want to, but you also
want to be able to have it not happen.

There's a huge amount of discussion of this in the mailing list
archives and on RCRchive. People disagree, irreconcilably, and it's
not worth rehashing the whole thing. But have a look at the archives
if you're interested.

David

···

On Thu, 8 Jun 2006, Alder Green wrote:

--
David A. Black (dblack@wobblini.net)
* Ruby Power and Light, LLC (http://www.rubypowerandlight.com)
   > Ruby and Rails consultancy and training
* Author of "Ruby for Rails" from Manning Publications!
   > Ruby for Rails

Alder Green wrote:

Hi

I'm confused as to why class methods aren't include'd by default along
with instance methods when mixing-in modules.

It obstructs the important orthoganility between modules and classes,
and - among other problems - thus undermines the position of mixins as
an alternative to class-based multiple inheritance.

In short, I can see a lot of poor consequence to that lack of support,
while on the other hand no good reason for it. Maybe someone would
care to elighten me?

(I'm aware of the various hacks for fudging such support, and in fact
use some of them in my code. But there are readability and
maintainability issues with those hacks for something that's supposed
to be a core feature).

You can do this without too much trouble. This is what I use, which is based off some code _why posted on his blog a while back.

---- meta.rb ----

# A set of methods to help create meta-programming gizmos.
class Object
   # The metaclass is the singleton behind every object.
   def metaclass
     class << self
       self
     end
   end

   # Evaluates the block in the context of the metaclass
   def meta_eval &blk
     metaclass.instance_eval &blk
   end

   # Acts like an include except it adds the module's methods
   # to the metaclass so they act like class methods.
   def meta_include mod
     meta_eval do
       include mod
     end
   end

   # Adds methods to a metaclass
   def meta_def name, &blk
     meta_eval { define_method name, &blk }
   end

   # Defines an instance method within a class
   def class_def name, &blk
     class_eval { define_method name, &blk }
   end
end

···

----------------------

require 'meta'

module Foo
   def test
     puts "test method"
   end
end

class Bar
   meta_include Foo
end

Bar.test
# >> "test method\n"

-Jeff

module M
   def self.new
     'yikes!'
   end
   def self.alloc
     'even worse'
   end
   def self.name
     'this is getting bad'
   end
   def self.is_a?
     'i hope you did not override this'
   end
end

class C
   include M
end

-a

···

On Thu, 8 Jun 2006, Alder Green wrote:

Hi

I'm confused as to why class methods aren't include'd by default along
with instance methods when mixing-in modules.

It obstructs the important orthoganility between modules and classes,
and - among other problems - thus undermines the position of mixins as
an alternative to class-based multiple inheritance.

In short, I can see a lot of poor consequence to that lack of support,
while on the other hand no good reason for it. Maybe someone would
care to elighten me?

(I'm aware of the various hacks for fudging such support, and in fact
use some of them in my code. But there are readability and
maintainability issues with those hacks for something that's supposed
to be a core feature).

--
-Alder

--
suffering increases your inner strength. also, the wishing for suffering
makes the suffering disappear.
- h.h. the 14th dali lama

Yes, I'm using this idiom in my code. Note, however, that if you want
to use A'd "class methods" from A itself, you have to add the extra
line:

self.extend(ClassMethods)

after A::ClassMethods's definition.

Still, it's unclear to me why this very natural functionality isn't
built into the default append_features. It hinders the ease of going
from a module to a class or vice-versa, which Ruby seems to encourage.
In any case, every other aspect of switching between those two is
well-handled, so why not this one as well? Are there plans to add it
for Ruby 2?

···

On 6/8/06, Phil Tomson <rubyfan@gmail.com> wrote:

On 6/7/06, Alder Green <alder.green@gmail.com> wrote:
> Hi
>
> I'm confused as to why class methods aren't include'd by default along
> with instance methods when mixing-in modules.
>
> It obstructs the important orthoganility between modules and classes,
> and - among other problems - thus undermines the position of mixins as
> an alternative to class-based multiple inheritance.
>
> In short, I can see a lot of poor consequence to that lack of support,
> while on the other hand no good reason for it. Maybe someone would
> care to elighten me?
>
> (I'm aware of the various hacks for fudging such support, and in fact
> use some of them in my code. But there are readability and
> maintainability issues with those hacks for something that's supposed
> to be a core feature).
>

The main reason is because a different 'self' is involved, I would guess.
You can use extend to mixin class methods. Also, there's a nice idiom
for getting include to mixin both class and instance methods of a
module (though the class methods are actually in another sub-module):

module A
  def self.included receiver
    receiver.extend ClassMethods
  end

  module ClassMethods
    def foo
      "foo"
    end
  end
  def inst_method
    "instance method"
  end
end

class B
  include A
end

B.foo #=> "foo"
B.new.inst_method #=> "instance method"

--
-Alder

Jeff Rose wrote:

Not the same thing.

require 'meta'

module Foo
   def test
     puts "test method"
   end
end

class Bar
   meta_include Foo
end

Bar.test
# >> "test method\n"

Why? You can just do

  class Bar
     extend Foo
  end
  
   Bar.test
  # >> "test method\n"

T.

Sigh. We've been through this Ara. It's a silly example --don't use
those methods if you don;t want to override them --and what if you do?

Nonethesless, I agree with Matz. I think a simple alternative call is
the prefect compromising solution. Perhaps:

class C
    inherit M
end

Also, This post is kind of timely, I'be been preparing a post with
example's from Nitro on the extensive need of this behavior --you
should see the many "hacks" being used to accomplish this there --I
think at least three different techinqes are being used throughout
dozens of components.

T.

···

ara.t.how...@noaa.gov wrote:

module M
   def self.new
     'yikes!'
   end
   def self.alloc
     'even worse'
   end
   def self.name
     'this is getting bad'
   end
   def self.is_a?
     'i hope you did not override this'
   end
end

class C
   include M
end

Hi,

···

In message "Re: Why the lack of mixing-in support for Class methods?" on Thu, 8 Jun 2006 17:02:35 +0900, "Alder Green" <alder.green@gmail.com> writes:

Still, it's unclear to me why this very natural functionality isn't
built into the default append_features.

Mix-in is used for several purposes and some of them can be hindered
by inheriting class methods, for example, I don't want to spill
internal methods when including the Math module. I am not against for
some kind of inclusion that inherits class methods as well, but it
should be separated from the current #include behavior.

              matz.

Sigh. We've been through this Ara. It's a silly example --don't use those
methods if you don;t want to override them --and what if you do?

indeed. still - i see it being a bit anti POLS from someone's perspective,
that's all.

Nonethesless, I agree with Matz. I think a simple alternative call is
the prefect compromising solution. Perhaps:

class C
  inherit M
end

i have my own impl :wink:

Also, This post is kind of timely, I'be been preparing a post with example's
from Nitro on the extensive need of this behavior --you should see the many
"hacks" being used to accomplish this there --I think at least three
different techinqes are being used throughout dozens of components.

the one issue i see is with stateful methods - we don't currently have
'inheritable state'. eg

   module M
     class << self
       attr 'foo'
     end
     @foo = 42
   end

   class A
     inherit M
   end

   class B < A
   end

   p M.foo #=> 42
   p A.foo #=> nil
   p B.foo #=> nil

   A.foo = 'forty-two'

   p M.foo #=> 42
   p A.foo #=> 'forty-two'
   p B.foo #=> nil

traits addresses this. eg this works

   require 'traits'

   class M
     class_trait 'foo' => 42
   end

   class A < M
   end

   class B < A
   end

   p M.foo #=> 42
   p A.foo #=> 42
   p B.foo #=> 42

   A.foo = 'forty-two'

   p M.foo #=> 42
   p A.foo #=> 'forty-two'
   p B.foo #=> 'forty-two'

not a deal breaker - but i've found in that in many designs relying on class
inheritence it's precisely this kind of information sharing one is trying to
acheive via inheritence or mixing in class methods.

just food for thought. if we start mixing in class methods then the strange
behaviour of ruby's 'class variables' and 'class instance variables' will
become a popular topic on this list.

cheers.

-a

···

On Thu, 8 Jun 2006 transfire@gmail.com wrote:
--
suffering increases your inner strength. also, the wishing for suffering
makes the suffering disappear.
- h.h. the 14th dali lama

indeed. still - i see it being a bit anti POLS from someone's perspective,
that's all.

Fair enough. No doubt it will come with it's own set of considerations
with which we progammers will have to become familiar.

> Nonethesless, I agree with Matz. I think a simple alternative call is
> the prefect compromising solution. Perhaps:
>
> class C
> inherit M
> end

i have my own impl :wink:

> Also, This post is kind of timely, I'be been preparing a post with example's
> from Nitro on the extensive need of this behavior --you should see the many
> "hacks" being used to accomplish this there --I think at least three
> different techinqes are being used throughout dozens of components.

the one issue i see is with stateful methods - we don't currently have
'inheritable state'. eg

   module M
     class << self
       attr 'foo'
     end
     @foo = 42
   end

   class A
     inherit M
   end

   class B < A
   end

   p M.foo #=> 42
   p A.foo #=> nil
   p B.foo #=> nil

   A.foo = 'forty-two'

   p M.foo #=> 42
   p A.foo #=> 'forty-two'
   p B.foo #=> nil

I think one would need to set that up oneself using a class variable.
Rather I would expext this it to behave like it does, just as with a
class:

  class X
    def self.x
      @x
    end
    @x = 10
  end

  class Z < X
  end

  X.x #=> 10
  Z.x #=> nil

traits addresses this. eg this works

   require 'traits'

   class M
     class_trait 'foo' => 42
   end

   class A < M
   end

   class B < A
   end

   p M.foo #=> 42
   p A.foo #=> 42
   p B.foo #=> 42

   A.foo = 'forty-two'

   p M.foo #=> 42
   p A.foo #=> 'forty-two'
   p B.foo #=> 'forty-two'

You bring up your traits library all the time :wink: Actually all-in-all I
think it's pretty good. Unfortuately I have this one nagging problem
with it. I think the term 'traits' is a terrible misnomer. That may
seem silly but having done some study of prototype-base OOPS,
especially Self, traits are just a totlatlly different concept to me.

T.

···

ara.t.howard@noaa.gov wrote:

Hi Matz :slight_smile:

I see your and Dblack's point about the need for an #include that
won't inherit the class methods. And I agree that it's probably a good
idea to keep #include behaving as it does right now. So adding a
separate #inherit seems like a very good idea.

I encountered the need for #inherit when I wrote Foo as a class, and
then later discovered I needed to have Foo features in class Bar that
already has parent Baz. It seems Ruby would be much more flexible if I
could simply:

module Fooable # instead of class Foo
  ...
end

class Foo
  inherit Fooable
end

class Bar < Baz
  inherit Fooable
end

This is not a rare need, at least not for me. I'm pretty new to Ruby,
and alredy needed to do this 5 times. Also I'd argue current lack of
support of this encourages programmers to encapuslate functionality in
classes even when they don't need to instantiate it, and a module
would be more appropriate.

Since you don't seem averse to the idea, and there are others (below,
in this thread, and earlier in other threads) who share the same need,
what do we need to do to have #inherit added as feature?

···

On 6/8/06, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

Hi,

In message "Re: Why the lack of mixing-in support for Class methods?" > on Thu, 8 Jun 2006 17:02:35 +0900, "Alder Green" <alder.green@gmail.com> writes:

>Still, it's unclear to me why this very natural functionality isn't
>built into the default append_features.

Mix-in is used for several purposes and some of them can be hindered
by inheriting class methods, for example, I don't want to spill
internal methods when including the Math module. I am not against for
some kind of inclusion that inherits class methods as well, but it
should be separated from the current #include behavior.

                                                        matz.

--
-Alder

I think one would need to set that up oneself using a class variable.
Rather I would expext this it to behave like it does, just as with a class:

class X
   def self.x
     @x
   end
   @x = 10
end

class Z < X
end

X.x #=> 10
Z.x #=> nil

right. it's just that 'inheritence' with object generally follows this
pattern

   class B
     attr :b
     def initialize() @b = 'bar' end
   end

   class C < B
   end

   p C.new.b #=> 'bar'

which is to say there are mechanisms, namely initialize and super, for
propagating state. no such mechanisms exist for class based state. if one is
proposing an 'inherit' method (which i think is a great idea) then i think
it's important to also toss around ideas for things like Class.class_init
and/or Module.module_init - eg hooks that are provided to accomplish this. my
preferred approach now is this

   module M
     module ClassMethods
       attr 'a'
       attr 'b'
     end
     module InstanceMethods
     end
     def self.included other
       other.extend ClassMethods
       other.module_eval{ include InstaneMethods }
       init other
     end
     def self.init other
       other.a = 42
       other.b = 'forty-two'
     end
   end

if we don't also consider this then the situation you describe in Nitro, where
there a muliple ways of implimenting class method mixins, will more or less
remain if any of those methods require state - that is to say it'd be a shame
to make every ruby developer roll his is own way of initializing the required
state for the module methods he could mix into his classes so easily.

You bring up your traits library all the time :wink:

yeah, not on purpose though: it just fills a lot of meta-programming and class
inheritence niches which seems to come up often on this list.

Actually all-in-all I think it's pretty good. Unfortuately I have this one
nagging problem with it. I think the term 'traits' is a terrible misnomer.
That may seem silly but having done some study of prototype-base OOPS,
especially Self, traits are just a totlatlly different concept to me.

well - you can use the 'has' interface

   class C
     has 'c' => 42
     class_has 'b'
   end

it's just an alias - but if you hate the name...

cheers.

-a

···

On Thu, 8 Jun 2006 transfire@gmail.com wrote:
--
suffering increases your inner strength. also, the wishing for suffering
makes the suffering disappear.
- h.h. the 14th dali lama

Hi,

···

In message "Re: Why the lack of mixing-in support for Class methods?" on Fri, 9 Jun 2006 00:49:19 +0900, "Alder Green" <alder.green@gmail.com> writes:

I see your and Dblack's point about the need for an #include that
won't inherit the class methods. And I agree that it's probably a good
idea to keep #include behaving as it does right now. So adding a
separate #inherit seems like a very good idea.

I don't like the name #inherit. Since it is not a inheritance.

              matz.

i've suggested 'mixin' in the past

   module M
   end

   class C
     mixin M
   end

??

-a

···

On Fri, 9 Jun 2006, Yukihiro Matsumoto wrote:

Hi,

In message "Re: Why the lack of mixing-in support for Class methods?" > on Fri, 9 Jun 2006 00:49:19 +0900, "Alder Green" <alder.green@gmail.com> writes:

>I see your and Dblack's point about the need for an #include that
>won't inherit the class methods. And I agree that it's probably a good
>idea to keep #include behaving as it does right now. So adding a
>separate #inherit seems like a very good idea.

I don't like the name #inherit. Since it is not a inheritance.

--
suffering increases your inner strength. also, the wishing for suffering
makes the suffering disappear.
- h.h. the 14th dali lama

right. it's just that 'inheritence' with object generally follows this
pattern

   class B
     attr :b
     def initialize() @b = 'bar' end
   end

   class C < B
   end

   p C.new.b #=> 'bar'

which is to say there are mechanisms, namely initialize and super, for
propagating state. no such mechanisms exist for class based state. if one is
proposing an 'inherit' method (which i think is a great idea) then i think
it's important to also toss around ideas for things like Class.class_init
and/or Module.module_init - eg hooks that are provided to accomplish this. my
preferred approach now is this

   module M
     module ClassMethods
       attr 'a'
       attr 'b'
     end
     module InstanceMethods
     end
     def self.included other
       other.extend ClassMethods
       other.module_eval{ include InstaneMethods }
       init other
     end
     def self.init other
       other.a = 42
       other.b = 'forty-two'
     end
   end

if we don't also consider this then the situation you describe in Nitro, where
there a muliple ways of implimenting class method mixins, will more or less
remain if any of those methods require state - that is to say it'd be a shame
to make every ruby developer roll his is own way of initializing the required
state for the module methods he could mix into his classes so easily.

Okay. I see what you're saying. Thouhg, I guess I'm thinking class
variables might help as far as carrying inheritable class level state.
Class variables are going to be "fixed" and made local to the
class/module right? So they will be able to be used for a class state
state. Is that right? And I think we all agree some sort of
module-based initialization could be helpful (though *I think* it's
hard to say how you do that for instance variables without thwarting
proper OOP).

well - you can use the 'has' interface

   class C
     has 'c' => 42
     class_has 'b'
   end

it's just an alias - but if you hate the name...

Better! *nodes head approvingly* :slight_smile:

T.

···

ara.t.howard@noaa.gov wrote:

Yukihiro Matsumoto wrote:

Hi,

>I see your and Dblack's point about the need for an #include that
>won't inherit the class methods. And I agree that it's probably a good
>idea to keep #include behaving as it does right now. So adding a
>separate #inherit seems like a very good idea.

I don't like the name #inherit. Since it is not a inheritance.

I knew you were going to say that :wink: I actually hesitated to suggest
it, but I haven't thought of anything better. But I would like to point
out an interesting (albiet currently illegal) equivalency:

  module Beanable
    def self.pod
      "oooooo"
    end
  end

  class Beanbag
    extend (class << Beanable; self; end)
  end

T.

···

In message "Re: Why the lack of mixing-in support for Class methods?" > on Fri, 9 Jun 2006 00:49:19 +0900, "Alder Green" <alder.green@gmail.com> writes:

Yukihiro Matsumoto wrote:

Hi,

>I see your and Dblack's point about the need for an #include that
>won't inherit the class methods. And I agree that it's probably a good
>idea to keep #include behaving as it does right now. So adding a
>separate #inherit seems like a very good idea.

I don't like the name #inherit. Since it is not a inheritance.

Why change the name of include, why not just give it some options. The
behavior is still the same, it is just the scope (singleton or instance
level methods) that is changing.

  include Foo # current behavior
              # (more explicitly 'include Foo, :instance_methods
  include Foo, :singleton_methods # include only singleton methods
  include Foo, :all # include both instance and singleton methods

I think it makes more sense to reuse the name include for this rather
then a new name, since the behavior isn't changing. Only the scope it
applies to.

One possible drawback of this is that it would always include singleton
methods at the class-level for the including class. And someone wouldn't
be able to use this to include a singleton method as an instance method
on a class. I personally wouldn't want to do this (seems way to
confusing), but perhaps someone else does.

Zach

···

In message "Re: Why the lack of mixing-in support for Class methods?" > on Fri, 9 Jun 2006 00:49:19 +0900, "Alder Green" <alder.green@gmail.com> writes:

I like that.

James Edward Gray II

···

On Jun 8, 2006, at 12:45 PM, ara.t.howard@noaa.gov wrote:

On Fri, 9 Jun 2006, Yukihiro Matsumoto wrote:

Hi,

In message "Re: Why the lack of mixing-in support for Class methods?" >> on Fri, 9 Jun 2006 00:49:19 +0900, "Alder Green" >> <alder.green@gmail.com> writes:

>I see your and Dblack's point about the need for an #include that
>won't inherit the class methods. And I agree that it's probably a good
>idea to keep #include behaving as it does right now. So adding a
>separate #inherit seems like a very good idea.

I don't like the name #inherit. Since it is not a inheritance.

i've suggested 'mixin' in the past

  module M
  end

  class C
    mixin M
  end

Um. I think that's too confusing. The problem is that we want to be clear that:

  * #include only deals with the inclusion of instance-level methods
at the instance level.
  * #extend only deals with inclusion of instance-level methods at the
class/object level.
  * #??? includes both instance- and class-level methods at the
instance/class level.

In my mind, #mixin does not capture that, since the process of
#include *or* #extend is called mixing-in.

No, I don't have a better name. I thought of #blend, but that's just
too ... ugly.

-austin

···

On 6/8/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:

On Fri, 9 Jun 2006, Yukihiro Matsumoto wrote:
> I don't like the name #inherit. Since it is not a inheritance.
i've suggested 'mixin' in the past

   module M
   end

   class C
     mixin M
   end

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