Let’s dig in a little more into self.

When running a script with the class Artist, we get this:

puts "before Artist - self: #{self}"

class Artist
  puts "inside Artist - self: #{self}"

  def initialize(name, genre)
    puts "inside initialize - self: #{self}"

    @name = name.capitalize
    @genre = genre
  end

  def introduce
    puts "inside introduce - self: #{self}"
    puts "I'm #{@name} and I sing - self: #{@genre}"
  end
end

puts "after Artist - self: #{self} "

before Artist - self: main
inside Artist - self: Artist
after Artist - self: main

If we run the same script with initializing a new object:

>> a = Artist.new("etta james", "blues")
>> puts a.introduce

before Artist - self: main
inside Artist - self: Artist
after Artist - self: main
inside initialize - self: #<Artist:0x007fa5fd05a370>
inside introduce - self: #<Artist:0x007fa5fd05a370>
I'm Etta james and I sing - self: blues

self is always the current object.


Here, self pointed to different current object:

  • Artist
  • instance of Artist
  • main

What is main ?

Ruby creates an object named main at the top level context whenever Ruby starts.

>> self
main
>> self.class
Object < BasicObject

So now if we call a method that does not exist in the Object class nor in its parent -BasicObject-, we get this famous error undefined local variable or method 'hello' for main:Object:

>> hello
Traceback (most recent call last):
        2: from /Users/cco/.rvm/rubies/ruby-2.5.3/bin/irb:11:in `<main>'
        1: from (irb):10
NameError (undefined local variable or method `hello' for main:Object)

Wait but what is Object ?

The documentation says:

Object is the default root of all Ruby objects. Object inherits from BasicObject which allows creating alternate object hierarchies. Methods on Object are available to all classes unless explicitly overridden.

If instead of calling the hello method, I try to call a constant refered into the Object class for exemple RUBY_VERSION, I get a value

>> RUBY_VERSION
"2.5.3"

Going back to the example above. Let’s add a puts for the self.class into our script, so we can follow what is self class:

before Artist - self: main - class: Object
inside Artist - self: Artist - class: Class
after Artist - self: main - class: Object
  • before Artist, self is the current object: main
  • inside Artist, self is the current object: Artist
  • afterArtist, self is the current object: main

What is self ?

self is a special variable that always refers to the current object

the current object is the default receiver


class Artist
  def initialize(name, genre)
    @name = name.capitalize
    @genre = genre
  end

  def introduce
    puts "I'm #{@name} and I sing - self: #{@genre}"
  end
end

a = Artist.new("etta james", "blues")
a.introduce

A method is a message that is sent to a receiver. Each time we call a method with an explicit receiver (any object)…

object.message


… in other words …

instance.method


… in other words …

explicit_receiver.method


…ruby follows these steps:

  1. It changes the default receiver to the explicit receiver for the current object.
  2. It looks at the available methods for this new current object.
  3. And invoke the method, going from class to parent class until it finds the invoked method.

What happens when we call a.introduce ?

In this example specifically, a. is an explicit receiver.

  1. Ruby changes self to be whatever is in a, so now self is pointing to the class Artist
  2. introduce is the only available method in Artist
  3. Instance variables always get stored in self, so when arriving to @name and @genre, self looks at the current object (object a as it is the explicit receiver for introduce), and finds the values that were stored during initialize.

Like we saw in Objects in Ruby (part II):

>> name = "norah jones"
"norah jones"

>> name.frozen?
false

As a reminder,

  • name does not have any singleton method named frozen?
  • the class of name is String
  • String does not have any method called frozen?
  • the parent of the class of String is Object
  • String doea have a method called frozen?
  • Bingo !

What happens with a class method ?

class Artist
  puts "inside Artist - self: #{self} - class: #{self.class}"

  def initialize(name, genre)
    @name = name.capitalize
    @genre = genre
  end

  def introduce
    puts "inside introduce - self: #{self} - class: #{self.class}"

    puts "I'm #{@name} and I sing - self: #{@genre}"
  end

  def self.hello
    puts "inside hello - self: #{self} - class: #{self.class}"

    puts "Hello #{@name}"
  end
end

a = Artist.new("etta james", "blues")
a.introduce
Artist.hello

we get:

inside Artist - self: Artist - class: Class
inside introduce - self: #<Artist:0x007f8dd9909d90> - class: Artist
I'm Etta james and I sing - self: blues
inside hello - self: Artist - class: Class
Hello
  • Inside introduce, self is pointing to the explicit receiver, which is the object a => self: #<Artist:0x007f8dd9909d90> - class: Artist
  • Inside hello, self is pointing to the explicit receiver, which is the object Artist => self: Artist - class: Class

Take Away:

  • Object is the default root of all Ruby objects.
  • Methods on Object are available to all classes unless explicitly overridden.
  • self gives you access to the current object, – the object that is receiving the current message.

Updated: