Where are the methods defined at the top level of the ruby?

At the top level, a method definition should result in private methods on Object , and tests seem to confirm this:

 def hello; "hello world"; end Object.private_instance_methods.include?(:hello) #=> true Object.new.send(:hello) #=> "hello world" 

However, at the top level, the following also works ( self.meta is eigenclass main ):

 self.meta.private_instance_methods(false).include?(:hello) #=> true 

It seems that the hello method is defined simultaneously on both the main and the Object . What's happening? Note that the false parameter on private_instance_methods excludes superclass methods from the list of methods.

+6
metaclass ruby singleton
source share
1 answer

First of all, this behavior and underlying reasoning have always existed; This is nothing new for 1.9. The technical reason why this happens is because main is special and is handled differently than any other object. There are no fashionable explanations: it behaves this way because it was designed that way.

OK, but why? What reasoning for main should be magical? Because Ruby designer Yukihiro Matsumoto believes that he makes the language better to have this behavior:

So, why top-level methods do not make singleton methods on this object, instead of being inserted as methods of an instance of the Object class itself (and, therefore, in all other classes, i.e. more namespace pollution than usual) . This will still allow top-level methods to invoke other top-level methods. And if some constant was referencing the top-level object, like Main, then these methods could be called from anywhere with Main.method (...).

Are you sure you want to enter "Main.print" everywhere?

Further in the discussion, he explains that he behaves this way because he feels that "the assumption is natural."

EDIT:

In response to your comment, your question is about why the main eigenclass seems to tell hello as a private instance method. The trick is that none of the top-level functions are actually added to main , but directly to Object . When working with eigenclasses, the instance_methods family of functions always behaves as if eigenclass is still the source class. That is, methods defined in a class are treated as defined directly in eigenclass. For example:

 class Object private def foo "foo" end end self.send :foo # => "foo" Object.private_instance_methods(false).include? :foo # => true self.meta.private_instance_methods(false).include? :foo # => true class Bar private def bar "bar" end end bar = Bar.new bar.send :bar # => "bar" Bar.private_instance_methods(false).include? :bar # => true bar.meta.private_instance_methods(false).include? :bar # => true 

We can add the method directly to main eigenclass. Compare the original example with this:

 def self.hello; "hello world"; end Object.instance_methods.include? :hello # => false self.meta.instance_methods.include? :hello # => true 

Ok, but what if we really want to know that the given function is defined on eigenclass and not on the source class?

 def foo; "foo"; end #Remember, this defines it in Object, not on main def self.bar; "bar"; end #This is defined on main, not Object foo # => "foo" bar # => "bar" self.singleton_methods.include? :foo # => false self.singleton_methods.include? :bar # => true 
+7
source share

All Articles