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?
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'.
You could define method in any order, the order doesn't matter anything.
In short: no, Ruby does not support nested methods.
In Ruby, methods are not objects.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With