What is "main" in Ruby?
Asked Answered
R

6

48

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?

Rori answered 27/5, 2009 at 20:16 Comment(2)
I feel like this question could benefit from the context of this one: stackoverflow.com/questions/916795Sidras
Asked by the same person. LOLStingy
P
54

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.

Perpetual answered 27/5, 2009 at 20:22 Comment(12)
Some of the other answers are saying that the "ruby interpreter" is calling the new method. But I think you're saying that there's an intermediate step before that happens. And that is that an instance of Object is created and all execution is mediated through that object. I'm really just trying to fill in the blanks in my understanding of how the "new" method gets passed as a message to the X object. From what you're saying it seems the main (Object instance) passes the new method as a message to the X Class instance. Am I getting closer?Rori
Well, I guess technically you can say it's the Ruby interpreter that does everything, since it's what actually executes your code. But from the standpoint of the language, yes, your description sounds exactly right. At the top level, when you first start typing in Ruby, you're in the context of that object. Most people don't use the top level like an object, but it is one.Perpetual
@steel Do you know where this magical behavior is documented?Impression
From the standpoint of the language? From the standpoint of Smalltalk? Maybe yes, the sender is the 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
I feel like w/o the other question/answer this one makes less sense.Mag
Added as an instance method of 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
Here's the declaration of the main object.Mag
I must confess I didn't like the "special property" part of your answer the first time I saw it. And at this point I don't see anything special about it. 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
@Mag Ordinarily, 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
...that a method you define becomes an instance method of 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
...I must admit here, that descriptions of 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
C
13

The top-level caller is an object main, which is of class Object.

Try this ruby program:

p self
p self.class
Cardio answered 27/5, 2009 at 20:30 Comment(0)
L
3

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:

  • creates a new class X which is a subclass of Object, and which automatically (as a subclass of Object) inherits some methods, of which new is one.
  • sets up a name x
  • calls the new method on that new class X, creating an X instance object; x gets a reference to that object.
Ludly answered 27/5, 2009 at 20:19 Comment(1)
"You're invoking the method "new"..." Jokingly or not, the question is, who are "you." :) Or rather, who is the sender.Mag
G
2

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.

Gunnysack answered 27/5, 2009 at 20:21 Comment(1)
Yeah, I think the person asking this question was referring to 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
R
1

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.

Raskind answered 27/5, 2009 at 20:23 Comment(2)
Do ruby -e "puts self". It will print "main". It's the top-level context object.Perpetual
my point was simply that you don't declare a main method, as the original poster seemed to imply in his question.Raskind
M
1

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.

Mag answered 10/1, 2023 at 7:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.