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.
main
object. Not sure, and not sure how applicable all that is here. Surely Ruby is influenced by Smalltalk. But to send a message explicitly we do X.send(:new)
, not send(X, :new)
. Neither that is the case in Smalltalk. And we have the caller
method, not sender
. So I think involving Smalltalk is far-fetched. And that's the terms I suggest to think in. main
is the caller. main
calls method new
on class X
. –
Mag Object
? I don't see that: ruby -e 'def m; end; p [Object.instance_methods.include?(:m), Object.methods.include?(:m), Object.new.methods.include?(:m)]'
gives [false, false, false]
. And do you know by any changes where main
is created in the ruby
source code? UPD I've got an answer to the first question. ruby -e 'def m; end; p Object.private_instance_methods.include?(:m)'
gives true
. That leaves the second one. –
Mag def
defines a method of some class/module. At the top level that's Object
. It would be special if at the top level def
defined a function. Also self
should refer to some object, unless you want to introduce a special case. At the top level that's the main
object. So I'd rather say that ruby
just follows suit. More on the way you can think about it in my answer. –
Mag def
defines a method on self
. So if the top level worked like any other context, def foo
would define a foo method for main
specifically, not for the Object class. For example, fake_main = Object.new; fake_main.instance_eval { def foo; "bar"; end }; fake_main.foo
works, but fake_main = Object.new; fake_main.instance_eval { def foo; "bar"; end }; foo
doesn't because the method only exists on fake_main
, not any other Objects. That's the special property I'm talking about. –
Perpetual Ordinarily, def defines a method on self
You can think of it that way. But that is an oversimplification. In reality def
defines methods on a cref
(class reference). You can use def
inside a method, and that would define an instance method, not a singleton method. Now if you imagine that ruby code is executed as part of a singleton method of an instance of Object
(main
), as I suggest in my answer, and as such cref
points to Object
, then it comes as no suprise... –
Mag Object
. But my abstraction is also leaky, and I bet you can't avoid special cases (sort of axioms) in any language... Anyways, I don't think I like your phrasing. To be precise and borrowing from the descriptions of class_eval
/instance_eval
, I'd say, "At the top level the code is executed within the context of the Object
class and self
points to an instance of Object
called main
." Or, "...within the scope of the Object
class..."... –
Mag class_eval
/instance_eval
are also confusing. "In the context" means or happens to mean different things there. Do they fear mentioning the word "singleton class"?.. In all these cases (top level, class_eval
, instance_eval
) you want to know where 2 things point to: cref
and self
. To not introduce unnecessary details you can call the first one scope/context. Anything less than that is an oversimplification, or vague wording. Or so I think. –
Mag 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
from the perspective of a C programmer. Everyone else here seems to be thinking of the top-level object named main
in Ruby, which isn't quite the same thing. –
Kathyrnkati 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.
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.
© 2022 - 2024 — McMap. All rights reserved.