Arup Rakshit
Arup Rakshit

Reputation: 118271

How `self` works in nested methods in ruby?

To see who is playing the role of self in nested methods, I tried the below code:

def test
  p "#{self}"
  def show
    p "#{self}"
  end
end
# => nil

As an effect, I got the two objects below:

Object.new.test
"#<Object:0x00000002212d78>"
# => nil
Object.new.test.show
"#<Object:0x00000002205330>" #<~~~ this is self understood
"" #<~~~ how this one came?
# => ""

But from the encoded numbers, I couldn't understand which class those objects belong to. And I tried the code below and got the respective class names.

Object.new.test.class
"#<Object:0x000000021ff3b8>"
# => NilClass
Object.new.test.show.class
"#<Object:0x000000020660b0>"
""
# => String

So can anyone help me to understand the concept of how the above code produced those class names?

EDIT

Here I tried to ask my question on more specific way:

def test
p "First level # => #{self}"
def show
p "Second level # => #{self}"
end
end
# => nil
Object.new.test.show
"First level # => #<Object:0x000000014a77b0>"
"Second level # => "
# => "Second level # => "
Object.new.test.show.class
"First level # => #<Object:0x0000000130ef70>"
"Second level # => "
# => String

Why the p "Second level # => #{self}" statement self has "" value?

Upvotes: 2

Views: 401

Answers (5)

Arup Rakshit
Arup Rakshit

Reputation: 118271

We all know that - self inside a method is always the object on which the method was called. So let's try and examine the truthfulness of that.

Let's see who is default self from the below code first of all:

m=self
# => main
m.class
# => Object

Okay, the default self is the object of Object class.

Just written the below code in more simplified way, from the description mentioned code,to highlight on the concept.

def test
p self.class
def show
p self.class
end
end
# => nil

Keeping in mind self inside a method is always the object on which the method was called called only test as below.

test
Object
# => nil

Yes, Object has been returned,on which the test has been called,that means the above statement is true.

test.show
Object
NilClass
# => NilClass

Calling to test also returns nil due to the block def show;p self.class;end.Now nil is an object of NilClass. Thus show method has been called on NilClass object. As result self is NilClass. Again the above statement holds.

With the above concept trying to reach to the actual goal with tiny steps:

def test
p "1. # => #{self}"
def show
p "2. # => #{self}"
end
end
# => nil

test
"1. # => main" #<~~ main is an object of class Object,on which test was called from IRB.
# => nil

test.show
"1. # => main"
"2. # => "    #<~~ nil("" means nil.to_s) is an object of Nilclass,on which show was called from IRB.
# => "2. # => "

Upvotes: 0

CCD
CCD

Reputation: 336

Object.new.test.show calls the show method in the Object.new.test object.

Object.new.test returns nil (as p returns nil), but at the same time it adds the definition of the show method to Object class.

As nil is of the class NilClass, which is a subclass of Object, nil has now show as a method, so you can actually call show in nil.

When you do Object.new.test.show is equivalent then to do

nil.show

When, within show, you do p "#{self}", you are actually printing nil.to_s

nil.to_s is ""

That explains that mysterious "" you see.

Upvotes: 3

Intrepidd
Intrepidd

Reputation: 20878

Try this :

class FooBar
  def foo
    puts self.class
    puts self
    def bar
      puts self.class
      puts self
    end
    bar
  end
end


FooBar.new.foo

I got :

FooBar
#<FooBar:0x007fc413849818>
FooBar
#<FooBar:0x007fc413849818>

You got different results since you allocated different objects.

self returns the object where the method is defined in, even if it's a nested method.

Upvotes: 1

pdoherty926
pdoherty926

Reputation: 10349

Try using: self.class.to_s. SO wants me to enter extra characters, so [:

Upvotes: 0

Roland Mai
Roland Mai

Reputation: 31077

It's rather straightforward:

def show
  p "#{self}"
end

returns nil, i.e. the def part, this is why the test method returns a nil object, an instance of the NilClass. Within the show method, you are doing p "#{self}" which will return a string object which is an instance of the String class.

Upvotes: 1

Related Questions