Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

methods

ruby

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?

like image 407
anthonygiuliano Avatar asked Sep 12 '16 15:09

anthonygiuliano


People also ask

What is explicit receiver in Ruby?

The object receiving the method call is the receiver. If you mention the object in the call, that's 'explicit'. If you call a method in the same object as the context without mentioning 'self', that's 'implicit'.

Does method order matter in Ruby?

You could define method in any order, the order doesn't matter anything.

Can you call a method inside a method Ruby?

In short: no, Ruby does not support nested methods.

Is a method an object in Ruby?

In Ruby, methods are not objects.


2 Answers

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.

like image 153
tadman Avatar answered Oct 12 '22 23:10

tadman


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.

like image 21
Jörg W Mittag Avatar answered Oct 13 '22 00:10

Jörg W Mittag