The power of Object private methods in Ruby
Tags: ruby, programming, beginners, tutorial
Published: 2022-02-22 07:13:07

We all know this simple and powerful method `puts`. Without diving into much details, it just outputs the object you provide it to the console. Almost every Ruby "Hello World" tutorial has this snippet of code.

Note: I'm using using Ruby `3.0.1`

```ruby
>> puts "Hello World"
Hello World
```

In short, every Ruby developer is familiar with this method. But, have you ever wonder why you can call this method everywhere without any receiver? (And not only `puts`, but also `p`, `print`, `rand`, `sleep` and a lot more)

## What is a receiver?

When you call a method in Ruby, you send a message to an object. The object that receives a message is called (drum roll...) a receiver! If an object has a method that corresponds to the message name, it's going to call that method. Here's a simple example.

```ruby
class Greeting
  def english
    "Hi"
  end
end
```
```ruby
>> greeting = Greeting.new
=> #<Greeting:0x00007f7a8f0f0da0>
>>
>> greeting.english
=> "Hi"
```

Here, `greeting` is the receiver. It receives the message `english`. It is able to respond to that message because it has the method that corresponds to it.

The most important thing is: _when you send a message(call a method), you always send it to some receiver(object). There's always a receiver. You can't send a message to no receiver._

By the way, we can use `send` method to call `english` method.  In such a way calling a method looks more like sending a message 😉

```ruby
>> greeting.send(:english)
=> "Hi"
```

Now that we know what the receiver is, let's get back to our beloved `puts`. Calling `puts` without any receiver looks more like calling a function, not a method. Maybe it's a function? But, Ruby is object oriented language, there are no functions... Nonetheless, I'm able to call `puts` everywhere without specifying a receiver. Why am I able to do that?

```ruby
>> puts "puts can be easily called from here"
puts can be easily called from here
>>
?> class A
?>   puts "and here"
>> end
and here
>>
?> module B
?>   puts "and of course from here"
>> end
and of course from here
>>
?> class C
?>   def c
?>     puts "long time no see"
?>   end
>> end
>> C.new.c
long time no see
```

To understand this, let's first understand what is an implicit receiver. 

## What is an implicit receiver?

Take a look at this example.

```ruby
class Greeting
  def english
    "Hi"
  end

  def call_english_without_receiver
    english # The implicit receiver is self.
  end
  
  # This method works the same as the above one.
  def call_english_with_receiver
    self.english
  end

  def get_implicit_receiver
    self
  end
end
```
```ruby
>> greeting = Greeting.new
=> #<Greeting:0x00007f7a8f0b8a18>
>>
>> greeting.call_english_without_receiver
=> "Hi"
>>
>> greeting.call_english_with_receiver
=> "Hi"
```

We send `call_english_without_receiver` message to the `greeting` object. `call_english_without_receiver` method sends `english` message without any receiver. If no receiver is specified, `self` becomes the receiver. Because of that, `call_english_with_receiver` works exactly the same as `call_english_without_receiver`. Simple enough. But, what is `self`? In our case it's the `greeting` object.

```ruby
>> greeting.get_implicit_receiver == greeting
=> true
```

There are three very important things to remember about an implicit receiver:
1. Whenever a message is sent without specifying a receiver, it will be sent to an implicit receiver.
2. The implicit receiver is always the `self` object.
3. `self` is present at any point in Ruby program. It changes when context does(basically, `self` is going to be different in a class, outside of a class, in a method... and so on).

```ruby
>> # Here self is the main object. It is always present
>> # outside of any methods, classes and modules.
>> p self
main
>>
?> class A
?>   # Here self is the class object.
?>   p self
>> end
A
>>
?> module B
?>   # Here self is the module object.
?>   p self
>> end
B
>>
?> class C
?>   def c
?>     # Here self is the class instance.
?>     p self
?>   end
>> end
>> C.new.c
#<C:0x00007f904e0afa10>
>>
>> C.new.c
#<C:0x00007f904e066748>
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/npjibkiwrvvztmuczhuz.jpeg) 

Okay, now we know that whenever `puts` message is sent(method is called) with no receiver, it is sent to the `self` object(called on the `self` object). But, `self` could be absolutely any object in Ruby. Does it mean that every object has `puts` method? The answer is YES. Every single object in Ruby responds to `puts` message.

## Why can all objects respond to `puts` message?

The first thing that I should point out is that all classes in Ruby inherit from `Object` class, which means that `Object` is a superclass of any class in Ruby. Let me show you an example. We can find out whether an object's class inherits from a certain class by using [kind_of?](https://rubyapi.org/3.0/o/object#method-i-kind_of-3F) method.

```ruby
>> 1.class
=> Integer
>> 1.kind_of? Object # Integer inherits from Object.
=> true
>>
>> [1].class
=> Array
>> [1].kind_of? Object # Array inherits from Object.
=> true
>>
?> class A
=> end
>> A.class
=> Class
>> A.kind_of? Object # Class inherits from Object 🤯
=> true
>>
?> module B
=> end
>> B.class
=> Module
>> B.kind_of? Object # Module inherits from Object 🤯
=> true
>>
>> self
=> main
>> self.class # main object is actually an instance of Object.
=> Object
>> self.kind_of? Object
=> true
>>
>> # You got the point :)
>> # Don't worry about examples with A class and B module 
>> # if you don't understand them.
>> # Basically, everything in ruby is an object.
>> # Which means that classes and modules are objects as well.
>> # And since every object has its class, we can 
>> # call #class method on any object.
```

You may ask, what does it have to do with `puts` method?
The thing is that `Object` class includes `Kernel` module, and `Kernel` defines `puts` method. It means that `puts` method becomes available for all instances of `Object` class and all instances of `Object` subclasses. Which means, `puts` becomes available for all objects! Isn't it awesome?

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bey31ma9zsalq1o5ogyy.jpeg)

```ruby
>> Object.kind_of? Kernel # #kind_of? also checks whether a module is included.
=> true
>>
>> Kernel.private_instance_methods.include? :puts
=> true
>> # Which means that Object must have #puts as well.
>>
>> Object.private_instance_methods.include? :puts
=> true
>>
>> Integer.private_instance_methods.include? :puts
=> true
>>
?> class A
>> end
>> A.private_instance_methods.include? :puts
=> true
```

But, wait a second! Why is `puts` private?

## If `puts` is private, why can we call it?

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q84s1vxnxb6x80fxo980.jpeg) 

What does it mean for a method to be private? It means that the method can only be called with an implicit receiver, or with `self`. Here's an example.

```ruby
class MyClass
  def my_public_method
    "Public"
  end

  def call_private_without_self
    my_private_method
  end

  def call_private_with_self
    self.my_private_method
  end

  private

  def my_private_method
    "Private"
  end
end
```
```ruby
>> obj = MyClass.new
>> obj.my_public_method
=> "Public"
>>
>> obj.my_private_method
private method `my_private_method` called for #<MyClass:0x00007fd43d219418> (NoMethodError)
>>
>> obj.call_private_without_self
=> "Private"
>>
>> obj.call_private_with_self
=> "Private"
```

See? I can't call `my_private_method` on `obj` object, because `obj` is the explicit receiver, and private methods does not allow that. I can only call `my_private_method` via `call_private_without_self` and `call_private_with_self`, because the first one uses the implicit receiver, and the second one uses `self`. And that's the main difference between public methods and private methods. Public methods can be called with an explicit receiver, an implicit receiver and with `self`. Private methods can only be called with an implicit receiver and with `self`.

Since `puts` is a private method just like `MyClass#my_private_method` method, the same rules apply to it.

```ruby
class MyClass
  def call_puts_without_self
    puts "Without self"
  end

  def call_puts_with_self
    self.puts "With self"
  end
end
```
```ruby
>> instance = MyClass.new
>> instance.call_puts_without_self
Without self
>>
>> instance.call_puts_with_self
With self
>>
>> instance.puts "You won't be able to call puts like this"
private method `puts` called for #<MyClass:0x00007fba20a67ae8> (NoMethodError)
```
```ruby
>> # Here's one more example.
?> class A
?>   puts "Without self"
?>   self.puts "With self"
>> end
Without self
With self
>>
>> A.puts "Ain't gonna print this"
private method `puts` called for A:Class (NoMethodError)
```
```ruby
>> # And here's a funny example :)
>> puts "Without self"
Without self
>>
>> self.puts "With self"
With self
>>
>> # Let's assign self to a variable.
>> main_obj = self
>>
>> main_obj.puts "Explicit receiver, it won't work anyway"
private method `puts` called for main:Object (NoMethodError)
>>
>> # Even though this is true. 
>> main_obj == self
=> true
```

And this is the reason why `puts` is always called without a receiver. Ruby language design allows us to not think about all those details and simply call `puts` like some magical function. And it's not only about `puts`, it's about all private methods you can find in `Object` class.

```ruby
>> methods = Object.private_instance_methods
>> methods.include? :raise # yeah, it's a method, not a keyword
=> true
>>
>> methods.include? :rand
=> true
>>
>> methods.include? :print
=> true
>>
=> # And so on... 
```

## Experiment and learn!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3gb7w6zueciguqx0t353.jpeg)

Let's try to experiment with what we learned about private methods in `Object` class.

```ruby
# Opening Object class to add a private method to it.
class Object
  private

  def debug_puts(str)
    puts "puts from #{self}: #{str}"
  end
end
```
```ruby
>> debug_puts "hello"
puts from main: hello
>>
?> class A
?>   debug_puts "hello"
>> end
puts from A: hello
>>
?> class B
?>   def b
?>     debug_puts "hello"
?>   end
>> end
>> B.new.b
puts from #<B:0x00007f88a2143368>: hello
```

I do not recommend doing something like this in a real project 😅, but it's always good to experiment. It helps you learn more.

## Conclusion

Isn't Ruby awesome? I've been programing in Ruby for quite a long time, and only recently I asked myself this question: "why do I call "puts" without any receiver?". The goal of this article is to not teach details of Ruby language design(I'm definitely not the one to do that 😆) but ask yourself questions if you don't understand something. You will learn a lot on the way of finding the answer. There's no magic in programing, everything has its explanation.