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

Austin Z. wrote:

Maybe it’s not optimal to make them singleton methods of Object, a
module would probably be better.

I could get behind that. Probably worth an RCR, I think.

I expiremented with that idea a while back when I was doing some work
on the BasicObject class. I expirementd with offering a variety of
“extenal” meta-programming methods as module methods of ObjectSpace.
And I also tried using global variable lambas, eg. $object_id[myobj].
While the former was more POLS, the globals actually proved nicer to
use.

Yet I’m not sure its the right approach. Is it that big a deal to have
a handful of __ methods? If so then maybe the milder appraoch of a
single non-overwriteable “self knowledge” method would be a good way,
‘myobj.self(:id)’ or even ‘myobj.self.id’ for instance.

T.

Hi–

On Fri, 16 Jun 2006, Yukihiro M. wrote:

|
end
end
module M2
include M
end
class C
include M2
end

M.foo # => NoMethodError
M2.foo # => Error? (should it affect modules?)

Yes, I think so.

C.foo # => Error? (should class_extension be propagated?)

I think not. The call to class_extension in M registers a policy on
the part of M. The policy affects M2, but it should not be shared by
M2.

If ‘class_extension’ affects modules as well, do you think of any
more generic name, in place of “class” extension?

Sean O’H. mentioned “extension”, which I think is as good as it will
get. (I’m still not a fan of this whole thing.)

David


David A. Black ([email protected])
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

See what the readers are saying about “Ruby for Rails”!

why the lucky stiff [email protected] writes:

figured out a better way to dispatch methods. Hey, let’s let them try.
And what if I still feel more meta than you? :wink:

Note that e.g. Ruby itself won’t call the updated definition of
send

On Sat, Jun 17, 2006 at 01:28:12AM +0900, Christian N. wrote:

Instead of further pythonizing the language (sorry, couldn’t resist),
I’d rather prefer a non-OO way for the tricky cases:

Object.object_id_of myobj
Object.class_of myobj
Object.send_to myobj, :foo

So, it quacks like a dog, but if we really press it, we can get a proper
fowlsome noise?

duck.quack
#<CryOfAlarm(“GAA! GAA!”)>

… uh… let’s try this again, that was a bit noisey

Animal.come_on_gimme_the_real_duck_quack duck
=> #

I’m not saying it’s a totally bad idea. I just don’t think I’d be able
to spot
when Object.object_id_of is necessary. I mean when in advance do you
know
you’re getting nasty mangled objects that don’t behave? I generally try
to use
send right now. I figure if send is overridden, then someone
has
figured out a better way to dispatch methods. Hey, let’s let them try.

_why

why the lucky stiff wrote:

figured out a better way to dispatch methods. Hey, let’s let them try.
I was looking over the Kernel methods, thinking about which one’s are
vital and and/or meta in nature. And really it seems like almost all of
them are, which probably accounts for why they are in Kernel to begin
with. They are (v1.8.4):

["==", “===”, “=~”, “id”, “send”, “class”, “clone”, “display”,
“dup”, “eql?”, “equal?”, “extend”, “freeze”, “frozen?”, “hash”, “id”,
“inspect”, “instance_eval”, “instance_of?”, “instance_variable_get”,
“instance_variable_set”, “instance_variables”, “is_a?”, “kind_of?”,
“method”, “methods”, “nil?”, “object_id”, “private_methods”,
“protected_methods”, “public_methods”, “respond_to?”, “send”,
“singleton_methods”, “taint”, “tainted?”, “to_a”, “to_s”, “type”,
“untaint”]

Looking through these, it really becomes hard to say what should stay
and what should go in forming a near empty class. And given their
nature one might be inclined to think that most of these should be
external to the object anyway. I mean, should the class really have the
“right” to override #object_id?

After thinking about this further. I started to wonder if maybe the
foo notation could be a special syntax Ruby would always take as a
method call bound to Kernel, analogous to:

def method_missing( meth, args, &blk )
if md = /^__(.
)__$/.match( meth.to_s )
Kernel.instance_method( md[1] ).bind(self).call(*args, &blk)
end
super
end

This example implmentation still allows them to be overridden. Whether
that should be so is debatible, though _why makes a good point. If you
think you can make a better quack than go for it.

Also interesting, If you look as Ruby 1.9 specs you’ll see there is now
a BasicObject that lies behind Object and Kernel. These are the methods
it isolates:

[ “send”, “funcall”, “id”, “==”, “send”, “respond_to?”,
“equal?”, “object_id”]

I’m all for the idea of a BasicObject b/c it will make OpenStruct and
classes of that ilk more standardized and robust. But I was wondering
what if you wanted to make a subclass of BasicObject but there were one
or perhaps a few other Kernel methods you needed to include. Say for
instance you needed #instance_variables. How would you be able to
include that since Kernel is not even in the class hiearchy? Maybe it
isn’t that important, but it doesn’t seem like it should be out the
question.

Of course, we take another step back we see that all of this crops up
b/c the OpenStruct pattern is just too damn nice not use, even though
Hash will usually work just as well. But who wants to do
foo[:a][:b][:c] when they can do foo.a.b.c? Moreover an OpenStruct can
quack like any duck; a hash can’t. But then the little edge problems
arise, b/c an OpenStruct pattern is generally used for something that
can have completely arbitarty keys. And that’s when the Kernel methods
can get in the way, not to mention any other internal methods you might
would like the class to have. So you clear out most of then methods
with BasicObject or BlankSlate or what have you and then some one elses
lib croaks b/c it can’t #dup you object or whatever. Yeah, it can get
nasty.

Okay, I’m starting to rattle on, but one last thought occurs to me:
might the whole issue go away if private and public methods could have
their own separate namespaces? The public method would still be
available privately, but if a specifcally private method of the same
name were defined it would be used when called without a receiver,
rather than the public one. The even for an OpenStruct one could
generally ensure the proper response from vital methods by using
#funcall.

T.

Hi,

In message “Re: Why the lack of mixing-in support for Class methods?”
on Thu, 15 Jun 2006 16:35:58 +0900, [email protected] writes:

|> I am not going to call “extend @class_extension” for the target
|> module. That’s not necessary, even bad from my eyes. I think this is
|> where our opinions differ.
|
|You mean to say you are going to eval the code directly into the target
|module instead?

No. I just said `I am not going to call “extend @class_extension” for
the target module’.

						matz.

Yukihiro M. wrote:

… I just said `I am not going to call “extend @class_extension” for
the target module’.

Let me get this straight:

module A
class_extension do
def foo
:foo
end
end
end

module B
include A
end

B.foo #=> NoMethodError

Correct? It would make the implementation a whole lot easier…

Daniel

Hi,

In message “Re: Why the lack of mixing-in support for Class methods?”
on Thu, 15 Jun 2006 17:16:01 +0900, Daniel S.
[email protected] writes:

|Let me get this straight:
|
| module A
| class_extension do
| def foo
| :foo
| end
| end
| end
|
| module B
| include A
| end
|
| B.foo #=> NoMethodError
|
|Correct? It would make the implementation a whole lot easier…

I meant A.foo would raise NoMethodError. Since class_extension
defines a part to inject into the inclusion target, I think B.foo
works as natural consequence of inclusion. If B.foo raises an error,
it makes class/module separation a lot wider than it currently is.
It is an interesting idea though.

						matz.

Yukihiro M. wrote:

No. I just said `I am not going to call “extend @class_extension” for
the target module’.

Okay. Whew. Scared me for a moment. Your last comment about me going
for “multiple inheritance” threw me --that’s not what I meant, I just
said I saw no adverse effect. But I see your point about the intent is
class injection. So that makes sense.

T.

Yukihiro M. wrote:

I meant A.foo would raise NoMethodError. Since class_extension
defines a part to inject into the inclusion target, I think B.foo
works as natural consequence of inclusion.

Splendid! That was also my first hunch. I’ll just fix my implementation
then…

Cheers,
Daniel