If I run this file as "ruby x.rb
":
class X
end
x = X.new
What is the thing that is calling "X.new
"?
Is it an object/process/etc?
If I run this file as "ruby x.rb
":
class X
end
x = X.new
What is the thing that is calling "X.new
"?
Is it an object/process/etc?
Everything in Ruby occurs in the context of some object. The object at the top level is called "main". It's basically an instance of Object with the special property that any methods defined there are added as instance methods of Object (so they're available everywhere).
So we can make a script consisting entirely of:
puts object_id
@a = 'Look, I have instance variables!'
puts @a
and it will print "105640" and "Look, I have instance variables!".
It's not something you generally need to concern yourself with, but it is there.
The top-level caller is an object main, which is of class Object.
Try this ruby program:
p self
p self.class
It's the X class. You're invoking the method "new" that creates an object of class X. So, if you run this text as a script, Ruby:
new
is one.x
new
method on that new class X
, creating an X instance object; x gets a reference to that object.It's the ruby interpreter running the line
x = X.new
As with many scripting languages, the script is interpreted from top to bottom rather than having a standard entry point method like most compiled languages.
main
is the object in the context of which the top level code is executed. Which means that self
at the top level refers to the main
object:
$ ruby -e 'p self'
main
And that ruby
follows the main
's method lookup chain to determine which method to call:
$ ruby -e 'p singleton_class.ancestors'
[#<Class:#<Object:0x00007f9e9fdee230>>, Object, Kernel, BasicObject]
There could be more, but that's what you get from the get-go.
main
itself is an instance of Object
:
$ ruby -e 'p self.class'
Object
It has a singleton class with 2 methods (a method and an alias to be more precise):
$ ruby -e 'p singleton_class.instance_methods(false)'
[:inspect, :to_s]
$ ruby -e 'p singleton_methods'
[:inspect, :to_s]
It's defined here.
As you can see its to_s
method returns "main"
(overrides the Object
's behavior), which is what you get when you do p self
.
You can think that the code you execute is put into a main
's method, after which the method is called. Along the lines of:
main = Object.new
class Object
def main.go
<your code here>
end
end
main.go
That is a rough idea. Let me justify it in a couple of steps.
In Ruby you can actually nest methods, but every time you call the outer method, the inner one gets defined/redefined. More importantly, it's defined as an instance method of the enclosing class:
class A
def m
def m2; end
end
end
A.new.m
p A.instance_methods(false) # [:m2, :m]
The same happens here, but the enclosing class in this case is the singleton class of A
:
class A
class << self
def m
def m2; end
end
end
end
A.m
p A.singleton_class.instance_methods(false) # [:m2, :m]
And what if we use the def self.<name>
notation?
class A
def self.m
def m2; end
end
end
A.m
p A.singleton_class.instance_methods(false) # [:m]
p A.instance_methods(false) # [:m2]
So, self.
affects only m
, m2
becomes an instance method of A
.
Actually, instead of self
there can be some random object:
o = Object.new
A = Class.new do
def o.m
def m2; end
end
end
o.m
p o.singleton_class.instance_methods(false) # [:m]
p A.instance_methods(false) # [:m2]
I had to use Class.new
because with class
o
wouldn't be visible inside the class definition.
Or actually I hadn't:
class A
o = Object.new
def o.m
def m2; end
end
o.m
p o.singleton_class.instance_methods(false) # [:m]
p A.instance_methods(false) # [:m2]
end
But let's ignore this branch of thought.
A couple of changes and you get this:
main = Object.new
Object.class_eval do
def main.go
@a = 1
def m2
puts @a
end
m2 # 1
end
end
main.go
p Object.instance_methods(false) # [:m2]
p main.instance_variables # [:@a]
I had to use class_eval
for it to not complain that I'm trying to redefine the Object
constant.
You can also add:
def main.to_s
"main"
end
main.instance_eval { alias inspect to_s }
for completeness.
Another way is to use global variables:
$main = Object.new
class Object
def $main.go
@a = 1
def m2
puts @a
end
m2 # 1
end
end
$main.go
p Object.instance_methods(false) # [:m2]
p $main.instance_variables # [:@a]
Of course variables main
/$main
and the go
method don't exist. But no more flaws come to mind when I think about this idea. The idea that it works as if your code is put into a main
's method and executed by running the method.
Also this kind of explains why methods defined at the top level are visible everywhere:
a.rb
:
f
$ ruby -e 'def f; puts "f"; end; require "./a"'
f
Because they become instance methods of Object
.
And you can use instance variables, which are instance variables of the main
object.
UPD I noticed that you can't define constants (in the usual way), classes and modules in main.go
. So the abstraction appears to be leaky. I might try to amend it:
Object.class_eval do
<your constants, classes, modules, methods>
def main.go
<the rest of the code>
end
end
But at this point I'd rather say, that at the top level self
points to the main
object, and the current class reference to the Object
class. More on class references here.
As Charlie Martin said, X.new is a call to the constructor on the X class, which returns an object of type X, stored in variable x.
Based on your title, I think you're looking for a bit more. Ruby has no need for a main, it executes code in the order that it sees it. So dependencies must be included before they are called.
So your main is any procedural-style code that is written outside of a class or module definition.