object_* and instance_* methods

T

Trans

another issue:

5) Doesn't encapsulate the original object.

I can offer a solution to that, though it still suffers some of the
other problems. I haven't tested this but it should work (and if not,
it can be fixed to do so):


require 'facets/more/namespace'

class Object

namespace :meta do

def send(obj, meth, *args)
Object.instance_method:)send).bind(obj).call(meth, *args)
end

def class(obj)
Object.instance_method:)class).bind(obj).call
end

# etc
end

end

class Foo
def send(*args)
"whoo!"
end
def class
"stupid!"
end
end

f = Foo.new

puts f.class # stupid!
puts f.meta.class # Foo

puts f.send:)object_id) # whoo!
puts f.send:)meta).send:)object_id) # -605608944

T.
 
D

David A. Black

Hi --
Problems 1 and 2b are, IMO, ultimately a symptom of all method names on an
object falling into the same namespace. The only way consistent way to
separate them is by including a namespace as part of the method name. Using
the object's class name would be one solution:

Object#object_class
Object#object_send
Object#object_private_methods
Object#object_singleton_method_added
...

There is already a precedent here: Object#id was renamed to Object#object_id

The precedent thing is always tricky, though. One could also say:
this has already happened once, so we've filled the quota :) Also, I
think #object_id was 100% about the difficulties with name conflicts,
which isn't an issue with #singleton_method_added.
However, a full solution to problem 2b would involve *all* methods on Object
being in a separate namespace. This quickly becomes stupid:

Object#object_is_a?
Object#object_nil?
Object#object_eql?
Object#object_to_s
...

Should it also apply to other built-in modules like Kernel (included in
every object) or Enumerable (included in many objects)?

Kernel#kernel_puts
Enumerable#enumerable_collect
... etc?

I think not. But if we choose some other basis for namespaces (e.g. "normal"
versus "metaprogramming") then again this crucially depends on recognising
which methods fall into which category, arguing this for each method.

And that's why I'd rather not get "meta" about it. It seems to me
that determining categorization for each method cannot be *better*
than determining what the method does and naming it based on that. In
particular, getting into an open-ended debate about what is and isn't
metaprogramming in Ruby is, I think, unpromising and wasteful.
Problem 7 is true of all keywords in the language, i.e. you can't have a
local variable or bare method name called 'if' or 'end'. It's a symptom of
keywords, local variables and receiverless method names falling into the
same namespace. I assume you don't want to tag these things Perl-style.

Since the set of reserved words in Ruby is very small, I don't think this is
a problem normally when choosing your own method names. But I agree that
it's unfortunate that Ruby has decided to use a name for a *built-in* method
which is also a reserved word.

From that point of view, I'd be happy to see #class changed to
#object_class, in the same way that #id was changed to #object_id

I'm personally in favor of #birth_class and #singleton_class, but I
don't think that has much traction.
(Incidentally, which of these are metaprogramming? What about "extend",
"taint", "freeze", "respond_to?")

Good question. My view is that it's all programming.[1] I think of the
term "metaprogramming", in connection with Ruby at least, as a
description of what the programming does, rather than what a given
method does.


David

[1] See, e.g., http://dablog.rubypal.com/2007/1/7/meta-shmeta-learning-ruby-horizontally

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
D

David A. Black

Hi --

I was just trying to make something which might be more palatable to the OP.

If I understand rightly, he would rather use foo#object_class,
foo#object_send, foo#object_method etc. as a way of lexically identifying
these methods as "meta programming methods". I showed how he could implement
exactly what he asks for, where he wants it, without demanding changes to
the core Ruby language.

However I agree with you - explicit reflections (which take an object as an
argument, rather than being methods on all objects) are probably a better
idea, to avoid the clutter.

I think the argument is moot unless Matz decides to go this way in a later
version of Ruby; otherwise we'll still have method soup anyway :)

But we don't. The method names in Ruby are hand-crafted with great
care, and they show it. Also, when there are soup-like tendencies,
Matz is eager and happy to discuss them.

(I see the smiley but I'm concerned that the drift of this thread
could be seen as: Matz botched the method-naming thing, so we have to
intervene and figure out how to fix it.)


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
B

Brian Candler

But we don't. The method names in Ruby are hand-crafted with great
care, and they show it. Also, when there are soup-like tendencies,
Matz is eager and happy to discuss them.

(I see the smiley but I'm concerned that the drift of this thread
could be seen as: Matz botched the method-naming thing, so we have to
intervene and figure out how to fix it.)

No, that wasn't intended at all.

I'm not arguing that the methods are badly named, although I sympathise with
the argument that #class awkwardly clashes with the 'class' keyword.

By "soup" I mean that even an empty object has a zillion methods inherited
from Object and Kernel. I don't dispute there are good reasons for each one;
e.g. if you had to write "$stdout.puts" instead of "puts", or
"Kernel.require 'foo'", those would be off-putting. All I'm saying is that
objects will always have these zillion methods, unless Matz decides to
modularise it, so adding a few more (like extra reflection methods under
your own naming scheme) wouldn't make any difference.

Matz *could* separate this all out:

class Object < BasicObject
include Kernel
include Reflection
... etc
end

But then, you still wouldn't get any benefit unless you explicitly created
your new objects under BasicObject rather than Object, so there's not much
practical benefit.

Regards,

Brian.
 
D

David A. Black

Hi --

I didn't write what follows so I guess the quoting got hosed :)
No, that wasn't intended at all.

I know; I was just concerned that, with the references to soup and
things being half-implemented and so on, people could get the
impression that this was all being ascribed to some failing on the
part of Matz. If so, that would be a meta-impression; I definitely
know that you're not saying that :)
I'm not arguing that the methods are badly named, although I sympathise with
the argument that #class awkwardly clashes with the 'class' keyword.

So do I. self.class is definitely not a high point. And the biggest
problem is probably that it brought about the creation of the #type
method, which to this day, I believe, makes it harder than it should
be for people to get the type != class thing.
By "soup" I mean that even an empty object has a zillion methods inherited
from Object and Kernel. I don't dispute there are good reasons for each one;
e.g. if you had to write "$stdout.puts" instead of "puts", or
"Kernel.require 'foo'", those would be off-putting. All I'm saying is that
objects will always have these zillion methods, unless Matz decides to
modularise it, so adding a few more (like extra reflection methods under
your own naming scheme) wouldn't make any difference.

Matz *could* separate this all out:

class Object < BasicObject
include Kernel
include Reflection
... etc
end

But then, you still wouldn't get any benefit unless you explicitly created
your new objects under BasicObject rather than Object, so there's not much
practical benefit.

There must be a way (though I'm multitasking too much right now to
figure it out) to do something like create your own modules that
consist of methods that already exist in other modules. Or something.
That would be kind of interesting.


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
B

Brian Candler

There must be a way (though I'm multitasking too much right now to
figure it out) to do something like create your own modules that
consist of methods that already exist in other modules. Or something.
That would be kind of interesting.

Hmm. Clearly this sort of stuff could go into a module; then anything which
is interested in reflections could do, say,

def process(a)
a.extend Reflection
a.instance_methods.each { ... }
...
end

Unfortunately, this causes a permanent change in the object being reflected
upon - an unintended Heisenberg-like side-effect.

However, suppose you could temporarily add a module:

def process(a)
b = a.insert Reflection
b.instance_methods.each { ... }
...
end

That would give an easy API, less cumbersome than Meta.instance_methods(a),
but not pollute the general method namespace of the object. Even better,
because the Reflection module was just inserted, when there is a name clash
then the method in Reflection will take precedence (e.g. b.class where a
already had overridden 'class')

I think this could be implemented using a proxy object / delegator.

But actually, there's no need to pass any method calls through. You could
just have a Reflector object:

def process(a)
b = Reflector.new(a)
b.instance_methods.each { ... }
...
end

B.
 
D

Daniel DeLorme

David said:
And that's why I'd rather not get "meta" about it. It seems to me
that determining categorization for each method cannot be *better*
than determining what the method does and naming it based on that. In
particular, getting into an open-ended debate about what is and isn't
metaprogramming in Ruby is, I think, unpromising and wasteful.

I'm starting to see your point. If we follow to its extreme the logic of
having a consistent prefix for all metaprogramming methods, we wind up
with a huge number of methods that can be considered to be
metaprogramming. Taking Object.instance_methods and removing aliases and
methods meant to be overridden, I get:

class
extend
freeze
frozen?
instance_eval
instance_of?
instance_variable_get
instance_variable_set
instance_variables
is_a?
method
methods
object_id
private_methods
protected_methods
public_methods
respond_to?
send
singleton_methods
taint
tainted?
untaint

Forcing all those methods to have an object_ or instance_ prefix is
self-evidently nonsense. Therefore being a metaprogramming method
*cannot* be the basis of using those prefixes.

But while I don't like the sound of "object_is_a?", I still like the
sound of "object_class" and "object_method". And I am starting to
realized that the reason is those methods represent /attributes/ of the
object while "is_a?" or "taint" are /actions/. In the case of
attributes, "object_" is not merely a prefix but an adjective to the
ambiguous noun "id". Same for "class" of "method". It makes the methods
sound natural, unlike slapping a prefix in front of an action verb. If I
follow that line of reasoning, object_send and instance_send may be bad
ideas. Unless we accept that some exceptions are inevitable, like
instance_variable_[gs]et.

Don't we just love semantics? ;-)

Daniel
 
R

Rick DeNatale

But while I don't like the sound of "object_is_a?", I still like the
sound of "object_class" and "object_method". And I am starting to
realized that the reason is those methods represent /attributes/ of the
object while "is_a?" or "taint" are /actions/.

How is is_a? an action? To me it looks like a predicate which is a
truth-valued function.

To me an action is something which, at least, potentially effects a
state change.

Not that you're wrong from your point of view, it's just evidence of
how tricky and personal such categorizations really are.
 
T

Trans

I'm starting to see your point. If we follow to its extreme the logic of
having a consistent prefix for all metaprogramming methods, we wind up
with a huge number of methods that can be considered to be
metaprogramming. Taking Object.instance_methods and removing aliases and
methods meant to be overridden, I get:
class
extend
freeze
frozen?
instance_eval
instance_of?
instance_variable_get
instance_variable_set
instance_variables
is_a?
method
methods
object_id
private_methods
protected_methods
public_methods
respond_to?
send
singleton_methods
taint
tainted?
untaint

Lets back up a second, these are "meta" because they are considered
"critical", right? The foremost reason for adding a prefix is simply
to make their name more uniq, so as be unlikely to clash with user-
defined method names. Most of these already fit that criteria. Any
that start with instance_ or object_ is uniq enough. And I would think
any of these having a punctuation mark is uniq enough as well. That
leaves:
class
extend
freeze
method
methods
private_methods
protected_methods
public_methods
send
singleton_methods
taint
untaint

Now I've always felt the methods, public_methods, private_methods and
protected_methods and singleton_methods were quite wasteful. One
method would suffice for all five, this has been discussed before. And
if we went ahead and did that and called that method #object_methods
and along with it had #object_method. Then all those are good to go
too. Leaving:
class
extend
freeze
send
taint
untaint

Now we all seem to agree that it at least makes sense to say
object_class to go along with object_id. And while I know there's
resistance to object_send (and instance_send) it makes a heck of a lot
of sense mnemonically. So if we could just go with that then there are
only four methods left:
extend
freeze
taint
untaint

I now sure about extend, but as for the last three. if these are
really critical then I'd take Daniel's idea about "action" to heart
and add a ! to them. They pretty much embody the idea of "danger"
methods.

freeze!
taint!
untaint!

There may be few methods forgotten here, and they can be considered,
but we're not after perfection --for that these methods would probably
have to be moved out of Object. But we at least gain a system much
improved.

T.
 
D

dblack

Hi --

Now we all seem to agree that it at least makes sense to say
object_class to go along with object_id. And while I know there's
resistance to object_send (and instance_send) it makes a heck of a lot
of sense mnemonically. So if we could just go with that then there are
only four methods left:

This reminds me of the routine where George Carlin reduces the ten
commandments to one :)
I now sure about extend, but as for the last three. if these are
really critical then I'd take Daniel's idea about "action" to heart
and add a ! to them. They pretty much embody the idea of "danger"
methods.

freeze!
taint!
untaint!

Action != danger :) Also, ! methods always come in pairs. That's
not enforced by the language, of course, but it's the convention: the
! indicates the dangerous version of a pair of methods where there's
also a non-dangerous version. Those three methods state clearly what
they do in their names, and they don't occur in pairs, so it's not a !
situation.


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
T

Trans

Hi --



This reminds me of the routine where George Carlin reduces the ten
commandments to one :)

Lol! :)
Action != danger :)

But what danger doesn't invlove action?
Also, ! methods always come in pairs. That's
not enforced by the language, of course, but it's the convention: the
! indicates the dangerous version of a pair of methods where there's
also a non-dangerous version. Those three methods state clearly what
they do in their names, and they don't occur in pairs, so it's not a !
situation.

I think that's just a general occurance. Not a rule. In anycase
there's a good reason for a different type of "danger" --don't
override me!

T.
 
D

dblack

Hi --

I think that's just a general occurance. Not a rule. In anycase
there's a good reason for a different type of "danger" --don't
override me!

Well... we'd have an awful lot of !'s if it started meaning that :)
I've never heard Matz discuss the ! in a way that made it sound like
he would use it outside of method pairs, and I'm still not sure what
the purpose would be. It's not a language-level rule, but I think
it's the intent behind the !.


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
T

Trans

I think this could be implemented using a proxy object / delegator.

But actually, there's no need to pass any method calls through. You could
just have a Reflector object:

def process(a)
b = Reflector.new(a)
b.instance_methods.each { ... }
...
end

I think that could be a damn good idea!

Is there room for two exceptions?

class Object
def object
@_object_reflector ||= Reflector.new(self)
end
def instance
@_instance_reflector ||= InstanceReflector.new(self)
end
end

foo.object.id
foo.instance.send:)P)

(*ducks*)
T.
 
D

Daniel DeLorme

Rick said:
How is is_a? an action? To me it looks like a predicate which is a
truth-valued function.

You are entirely right of course. I was thinking of "verb", really, and
incorrectly converted that to "action" when in fact not all verbs are
actions.

foo.method == foo's method (noun). what kind of method?
-> foo.object_method
-> foo.instance_method
-> foo.birth_control_method
foo.send(message) == foo sends (verb) a message. what kind of message?
-> foo.send_object(message)
-> foo.send_instance(message)
-> foo.send_email(message)

But even Matz chose instance_variable_get over get_instance_variable...

Daniel
 
D

Daniel DeLorme

Trans said:
Now I've always felt the methods, public_methods, private_methods and
protected_methods and singleton_methods were quite wasteful. One
method would suffice for all five, this has been discussed before. And
if we went ahead and did that and called that method #object_methods

I kinda like that a little bit. We could have
foo.object_methods.all/to_a
foo.object_methods.private
foo.object_methods.protected
foo.object_methods.public
foo.object_methods.singleton

But I'm not too concerned with "clutter". A basic Object could have a
bazillion methods as far as I care, as long as they don't conflict with
methods names that people can reasonably/possibly create on their own.
"private_methods" already has the adjective "private" to qualify the
ambiguous noun "methods", so changing that adjective to "object" is not
much of an improvement. Adding an adjective to "methods" would be good
but that is already done; methods is just an alias of public_methods.

Daniel
 
A

Austin Ziegler

- avoids ugliness like __send__

__send__ was *supposed* to be ugly, because it's a signal that you're
doing something different.
- reduces chances of naming conflict (CgiRequest#method, Email#send)

Naming conflicts are okay, as long as there are non-conflicting names
(e.g., __send__ or whatever 1.9 is now calling it).
- allows simple pattern match to recognize present and future
meta-programming methods (used for forwarding of non-meta methods)

Erm. Pattern matching is somewhat useful, but I'm not sure that this
is something that would be automatic in any case.

-austin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,209
Messages
2,571,088
Members
47,686
Latest member
sparada

Latest Threads

Top