anthonygiuliano anthonygiuliano - 2 months ago 13
Ruby Question

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

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
main
s 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?

Answer

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.

Comments