Is it equivalent to define a method in the main environment:
def foo; end
and to define it as Object
's instance method:
class Object
def foo; end
end
or is there a way to distinguish them?
Is it equivalent to define a method in the main environment:
def foo; end
and to define it as Object
's instance method:
class Object
def foo; end
end
or is there a way to distinguish them?
When you don't specify an object in whose singleton class the method should be defined, i.e. when you don't say
def bar.foo; end
but just
def foo; end
then the method gets defined in what is called the default definee. Normally, the default definee is the lexically enclosing module
, but at the top-level, it is Object
and the methods become private
by default. (The default definee can also be changed by various meta-programming methods.)
So, the two snippets you posted are not equivalent, because the first will define a private
method, and the second one a public
method:
def foo; end
method(:foo).owner
# => Object
Object.private_instance_methods(false).include?(:foo)
# => true
but
class Object; def foo; end end
method(:foo).owner
# => Object
Object.private_instance_methods(false).include?(:foo)
# => false
Note that in IRb and some other REPLs top-level methods may end up public
. That's a well-known incompatibility leaking a private internal implementation detail of those REPLs and not an official part of Ruby's semantics.
For me running a few tests I see methods being defined in the context of main
as being set as private_instance_methods
of Object
not public_methods
. This means unless you specifically define a private instance method on Object
you should be able to distinguish them.
Strangely I cannot confirm the other posts showing that these are public methods of Object. If anyone has any insight on this I would love to understand. (Maybe it has something to do with the use of pry
?)
I get the same in 1.9.3, 2.0.0, 2.1.5, and 2.2.3 so I am unsure why others get a different response.
/scripts/test.rb
puts "RUBY_VERSION: #{RUBY_VERSION}"
puts 'def foo; "in Main";end'
def foo; "in Main";end
puts "foo method response: #{foo}"
puts "Object.private_instance_methods:#{Object.private_instance_methods(false).inspect}"
puts "Trying to call Object.new.foo"
Object.new.foo
(Raw Output):
ruby 1.9.3p551 (2014-11-13) [i386-mingw32]
RUBY_VERSION: 1.9.3
def foo; "in Main";end
foo method response: in Main
Object.private_instance_methods:[:foo]
Trying to call Object.new.foo
/scripts/test.rb:7:in `<main>': private method `foo' called for #<Object:0x640368> (NoMethodError)
ruby 2.0.0p247 (2013-06-27) [x64-mingw32]
RUBY_VERSION: 2.0.0
def foo; "in Main";end
foo method response: in Main
Object.private_instance_methods:[:foo]
Trying to call Object.new.foo
/scripts/test.rb:7:in `<main>': private method `foo' called for #<Object:0x00000002d34b98> (NoMethodError)
ruby 2.1.5p273 (2014-11-13 revision 48405) [i386-mingw32]
RUBY_VERSION: 2.1.5
def foo; "in Main";end
foo method response: in Main
Object.private_instance_methods:[:foo]
Trying to call Object.new.foo
/scripts/test.rb:7:in `<main>': private method `foo' called for #<Object:0x2bec750> (NoMethodError)
ruby 2.2.3p173 (2015-08-18 revision 51636) [i386-mingw32]
RUBY_VERSION: 2.2.3
def foo; "in Main";end
foo method response: in Main
Object.private_instance_methods:[:foo]
Trying to call Object.new.foo
/scripts/test.rb:7:in `<main>': private method `foo' called for #<Object:0x593808> (NoMethodError)
Ruby 2.2.1.
self
#=> main
self == Object
#=> false
Object === self
#=> true
So main
is an instance of Object
.
main
is not equal Object
- these are different things.
Defined methods in main
and Object
def foo; end
self.class.instance_methods(false)
#=> [:pry, :__binding__, :foo]
class Object
def bar; end
end
#=> :bar
self.class.instance_methods(false)
#=> [:pry, :__binding__, :foo, :bar]
are both available for main
and new instances of Object
:
foo
#=> nil
bar
#=> nil
Object.new.foo
#=> nil
Object.new.bar
#=> nil
We can check the owner of the method defined in main
(which occurs to be Object
):
method(:foo).owner
#=> Object
It kind of implying you can't distinguish between methods defined in main
and Object
.
On Ruby 2.2.1 it becomes Object
's public instance method:
Object.public_method_defined?(:foo)
#=> true
In the end, they seem to be equivalent, as Andrey Deineko's answer tells. However, my concern was that defining a method on main
should result in defining an instance method on main
's singleton class, which is distinct from the class Object
. For example, if I define a method on an ordinary object, I can see that it becomes an instance method of its singleton class:
s = ""
def s.bar; end
s.singleton_class.instance_methods(false) # => [:bar]
However, with main
, it is different. Defining a method on main
does not result in it becoming an instance method of its singleton class. The returned list does not include :foo
:
def foo; end
singleton_class.instance_methods(false)
# => [:inspect, :to_s, :source, :kill, :exit, :conf, :context, :irb_quit, :quit, :irb_print_working_workspace, :irb_cwws, :irb_pwws, :cwws, :pwws, :irb_current_working_binding, :irb_print_working_binding, :irb_cwb, :irb_pwb, :irb_chws, :irb_cws, :chws, :cws, :irb_change_binding, :irb_cb, :cb, :workspaces, :irb_bindings, :bindings, :irb_pushws, :pushws, :irb_push_binding, :irb_pushb, :pushb, :irb_popws, :popws, :irb_pop_binding, :irb_popb, :popb, :jobs, :fg, :help]
So it looks like the method jumps the singleton class of main
and is directly defined on Object
. Hence, they cannot be distinguished.