Ruby what class gets a method when there is no explicit receiver?

北城以北 提交于 2020-04-10 17:35:41

问题


random question here. I'm not sure if there's a term for this, but I'm wondering when you define a method without an explicit receiver, how can you know what class gets the method? Is it whatever self is in that context?

self in the context of a class definition is the class being defined, and methods defined with an implicit receiver are bound to the class, which we see all the time.

But, if I define a method inside an instance method, that 'sub_method' is getting put on the outer class as well:

[12] pry(main)> class A
[12] pry(main)*   def my_method
[12] pry(main)*     puts self
[12] pry(main)*     def sub_method
[12] pry(main)*       puts self
[12] pry(main)*     end  
[12] pry(main)*   end  
[12] pry(main)* end  
=> :my_method
[13] pry(main)> a = A.new
=> #<A:0x007fa588181d40>
[14] pry(main)> a.my_method
#<A:0x007fa588181d40>
=> :sub_method
[15] pry(main)> a.sub_method
#<A:0x007fa588181d40>
=> nil
[16] pry(main)> A.instance_methods(false)
=> [:my_method, :sub_method]

Also at the top level scope, self is main, which is an instance of the Object class, but methods defined there are added to Object, not to mains singleton class, which is what I was expecting based on how I've seen other singleton methods work:

[21] pry(main)> def a.my_singleton
[21] pry(main)*   puts self
[21] pry(main)* end  
=> :my_singleton
[22] pry(main)> a.singleton_methods
=> [:my_singleton]
[23] pry(main)> A.instance_methods(false)
=> [:my_method, :sub_method]

[33] pry(main)> def why_object?
[33] pry(main)*   puts self
[33] pry(main)* end  
=> :why_object?
[34] pry(main)> why_object?
main
=> nil
[35] pry(main)> Object.instance_methods(false)
=> [:pry, :__binding__, :my_method, :sub_method, :why_object?]

What is going on here, is there a rule to this or are there just these few cases to know about?


回答1:


There are three implicit contexts in Ruby.

The most well-known is self, the current object and the default receiver.

The second well-known is the scope used for constant lookup. Broadly speaking, constant lookup is "lexically outward, then upward by inheritance", but there are many nuances. The Ruby maintainers call this context cref.

What you are asking about, is the third context, sometimes called the default definee. Usually, the default definee is the nearest lexically enclosing module. But, you already found one exception: at the top-level, the default definee is actually Object (plus, the default visibility is private). instance_eval changes both self (to the receiver of the instance_eval message) and the default definee (to the receiver's singleton class). class_eval changes both to the receiver.




回答2:


I think you're confusing "receiver" as in "receiver of messages" which is what people usually mean by the term and "receiver" as in "destination context for any methods defined".

Calling def inside a method is allowed by the syntax but unorthodox in terms of style. The Ruby way of doing this is using define_method where you have more control over where that method goes. Think of def as a simple way of defining methods, but where the context is a little slippery. If called in a class context it defines an instance method. If called inside an instance method it defines another instance method.

Even better is to wrap that method up in a module you can later include or extend something with as you see fit.

Defining methods at the top-level scope, on main, means you want them universally available. The best way to do that is to force them into Object. This is why defining methods in that context can get messy in a hurry so it's not recommended for anything other than trivial programs.



来源:https://stackoverflow.com/questions/39453741/ruby-what-class-gets-a-method-when-there-is-no-explicit-receiver

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!