A. N. Other
A. N. Other

Reputation: 489

What is the object in Ruby's "hello world"?

If everything is an object in Ruby, to the point that even math operators are methods applied to objects, when I write:

puts "Hello world"

The method is puts, and the parameter is "Hello world", but what is the object?

Upvotes: 7

Views: 713

Answers (3)

Jörg W Mittag
Jörg W Mittag

Reputation: 369536

If everything is an object in Ruby,

That is slightly misleading wording. E.g. syntax is not an object, blocks aren't objects, a conditional expression is not an object.

A better phrasing would be: "every value is an object".

to the point that even math operators are methods applied to objects, when I write:

puts "Hello world"

The method is puts, and the parameter is "Hello world", but what is the object?

There are two objects involved. I suspect what you really meant to ask is "what is the receiver object". (Actually, there are many more objects involved, but let's focus on the receiver and the argument for now.)

A message send always has a receiver object, i.e. the object that you send the message to. If the receiver object is not explicitly written out, it is implicitly assumed to be self (a pseudo-variable that always evaluates to the "current object"). Now, the question is: what (or "who") is self here?

This, by the way, is one of the most important questions you should ask yourself when writing Ruby code. Receiverless message sends are to self, instance variables are looked up in self. You should always be aware of which object self is at the point where you are writing your code.

In this particular case, when you write code at what Rubyists call the top-level, self is a pre-defined object Rubyists call main. It doesn't actually have a name, and there is no default reference to it, but 'main' is what it returns when you inspect it or convert it to a string using to_s:

to_s
#=> 'main'

inspect
#=> 'main'

The second object you already correctly identified: it is the String object resulting from the evaluation of the string literal "Hello World".

There are, however, more objects involved here. For example, main is an instance of Object, so Object must exist, too. "Hello world" is an instance of String, String must exist. String and Object are both classes, i.e. objects which are instances of the Class class, so Class must exist. Object's superclass is BasicObject. Class's superclass is Module. Object mixes in Kernel (which is an instance of the Module class). Kernel#puts returns nil, which is an instance of NilClass. Kernel#puts is just a helper method that delegates to IO#puts by calling $stdout.puts.

So, in addition to main and "Hello world", at least the following objects are also involved: nil, NilClass, String, Class, Module, Object, Kernel, BasicObject, IO, and the IO object assigned to the global variable $stdout, representing the standard output stream of your Ruby process.

That's 12 objects which are directly and intimately involved in the execution of your code snippet.

In reality, there are many more objects in even a simple Ruby program:

ruby --disable-gems --disable-did_you_mean -e 'p ObjectSpace.count_objects[:TOTAL]'

On my system, this prints a number around 9780 objects. Now, some of those are the Hash created by ObjectSpace::count_objects and the keys and values inside that Hash (such as the Symbol object :TOTAL), and of course the String created by trying to print out the result. But that's on the order of about ~35 objects, so there's still almost 10000 objects involved in the execution of, well, basically an empty program that does nothing.

Upvotes: 10

Eric Duminil
Eric Duminil

Reputation: 54263

puts

To find a method, you could call :

method(:puts)
#=> #<Method: Object(Kernel)#puts>

So puts is a method defined in Kernel, available to every Object.

Kernel#puts

puts "Hello world"

is actually

self.puts( String.new("Hello world") )

Where self is the object main.

So puts "hello world" is a :

  • Kernel#puts method call
  • on main
  • with a String object as argument.

Notes

Note that if you execute

self.puts( String.new("Hello world") )

you'll get an error :

private method `puts' called for main:Object (NoMethodError)

Because every Kernel method is made available to every Object, but as a private method. You'd need :

self.send(:puts, String.new("Hello world") )

Test

Another way to check would be :

module Kernel
  def my_puts(*args)
    print "Calling Kernel#my_puts on #{self} with #{args}\n"
    print "Now delegating to Kernel#puts on #{self} with #{args} :\n"
    puts(*args)
  end
end

my_puts "Hello world"

It outputs :

Calling Kernel#my_puts on main with ["Hello world"]
Now delegating to Kernel#puts on main with ["Hello world"] :
Hello world

See? Everything is an object, even though it might not look like it.

2+3

In the same vein : 2+3 is actually Integer(2).+( Integer(3) ).

Upvotes: 11

"Hello world" is the string object defined as a literal constant given as argument to the puts method

puts "Hello world" is in fact a simple way to do

puts myFoo

where myFoo must be a valid object... in your case myFoo = "Hello world"

Upvotes: 1

Related Questions