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).
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
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?
In message “Re: Why the lack of mixing-in support for Class methods?”
on Thu, 8 Jun 2006 17:02:35 +0900, “Alder G.” [email protected] 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.
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.
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
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
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
def self.is_a?
‘i hope you did not override this’
end
end
class C
include M
end
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.
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
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.
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.
from Nitro on the extensive need of this behavior --you should see the many @foo = 42
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
p M.foo #=> 42
p A.foo #=> ‘forty-two’
p B.foo #=> ‘forty-two’
You bring up your traits library all the time 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.
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
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.
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.
Hi Matz
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?
In message “Re: Why the lack of mixing-in support for Class methods?”
on Fri, 9 Jun 2006 00:49:19 +0900, “Alder G.” [email protected] 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 don’t like the name #inherit. Since it is not a inheritance.
I knew you were going to say that 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
module ClassMethods
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).