3

If I define a top-level method in a Ruby file, the value of self seems to depend heavily on who is calling it.

def who_am_i
  puts self.inspect
end

class A
  def self.foo
    who_am_i
  end
  def foo
    who_am_i
  end
end

def foo
  who_am_i
end

foo       # >> main
A.foo     # >> A
A.new.foo # >> #<A:...>

Obviously, if a method is defined in a class, self will either be the class itself (for class methods) or the relevant instance of the class (for instance methods). It seems, based on the trials shown above, that a method not defined in a class inherits self from its caller, but I can't find any official reference or anything to back that up. Can someone provide an official source that describes this behavior and ideally a rationale for why it works this way?

sawa
  • 165,429
  • 45
  • 277
  • 381
Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116

3 Answers3

3

All methods defined in the context of main object, will become [private] methods on Object. And since everything is an Object, this method will be available everywhere. And this is also why self is changing based on where you call it from: those are all different objects, but they also all inherit this method.

private_methods.include?(:who_am_i) # => true
foo       # => "main"
A.private_methods.include?(:who_am_i) # => true
A.foo    # => "A"
A.new.private_methods.include?(:who_am_i) # => true
A.new.foo # => "#<A:0x00007feaad034e00>"
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
1

Ruby creates an object called main whenever the Ruby starts and main is the top level context (aka top level scope) of the Ruby program. Methods defined in the top level scope (i.e. methods that are not wrapped in a class or module) will be bound to the main object.

More reference here and here

jedi
  • 2,003
  • 5
  • 28
  • 66
  • 2
    Yes, @CarySwoveland In Ruby everything is an object, even `main`. Simple check: open up `irb` and type `self` # => `main` and then `self.class` # => `Object` – jedi Jul 28 '18 at 08:17
  • Sorry, `main` is clearly an object, an instance of `Object`. (WWIT?) – Cary Swoveland Jul 29 '18 at 08:18
  • @jedi: "everything is an object" - blocks aren't objects (and probably one or two other things as well). A better assertion is "_most everything_ is an object" :) – Sergio Tulentsev Jul 30 '18 at 14:46
  • "blocks aren't objects" - Blocks _are_ objects. They are instances of Proc. `def t(&block) block.class.ancestors end; t {}` returns `[Proc, Object, Kernel, BasicObject]` – Steve Oct 16 '22 at 13:18
1

Yeah, as jedi mentioned, in ruby you are always in a context of some object. There's no such thing as function in ruby, only methods. And methods are defined on some object (on its class or singleton class to be precise).

You can think of main as you would run your program this way:

main_obj = Object.new
main_obj.instance_eval do
  # your program goes here

  # this defines method on `main_obj` singleton class
  def f
    puts 123
  end

  f
end

I guess you can read this question

Nondv
  • 769
  • 6
  • 11