Xavier
Xavier

Reputation: 323

Ruby - reference of self in the class method

Went over this code on RubyMonk:

 class Item
   def initialize(item)
     @item = item
   end
   def show
     puts "The item name is: #{self}"
   end
   def to_s
     "#{@item}"
   end
 end

 Item.new("potion").show

The code passes but the use of the self variable is a bit ambiguous to me. You could've easily supplanted to_s with self in the show method and gotten the same results. Can somebody explain the difference between both interpolations and why/how self is used here? Additionally, without the the method to_s, the code returns a proxy. What is the significance of defining the to_s here?

Upvotes: 3

Views: 1469

Answers (2)

UnlimitedHighground
UnlimitedHighground

Reputation: 760

While it's true that, in the example you provided, you could have just written "The item name is: #{@item}", that's not always the case.

As CDub points out, string interpolation implicitly calls to_s. If an object doesn't define a to_s method, Ruby returns an object reference in its place. In the example you gave us, writing "The item name is: #{@item}" only works because String implements to_s. If it didn't, or if you use Item to hold an object that doesn't implement to_s, you'll end up with the object's reference.

Now for the difference between using self and @item in your interpolation. self refers to the current object. When you interpolate self, you're calling the current object's to_s method. When you interpolate @item, you're calling @item's to_s method. That's not a problem in this simple case, but let's look at something a little bit more complex. Say we have two classes, Item and OtherItem (creative names, I know).

 class Item
   def initialize(item)
     @item = item
   end
   def show
     puts "The item name is: #{self}"
   end
   def to_s
     "I'm a chunky monkey!"
   end
 end

  class OtherItem
   def initialize(item)
     @otherItem = item
   end
   def to_s
     "#{@otherItem}"
   end
 end

In this scenario, Item's show method uses self, so if we were to write:

Item.new(OtherItem.new("potion")).show

Ruby would call Item.show, which, in turn, would call self.to_s. Since self in that context is an Item, our output would be:

"The item name is: I'm a chunky monkey!"

If, however, we redefined Item.show like this:

def show
  puts "The item name is: #{@item}"
end

And tried calling Item.new(OtherItem.new("potion")).show again, Item.show would call @item.to_s, and fill that in instead, so we'd get:

"The item name is: potion"

Upvotes: 1

CDub
CDub

Reputation: 13344

String interpolation implicitly calls the to_s method on an object. So, when you define the to_s method on Item, you are explicitly telling that object how to represent itself with respect to a string. self is used in this case because there is an implicit call to to_s within the interpolation of the Item object. Defining to_s explicitly tells Item how to render itself within a string.

For some additional details, check out this excellent post on explicit vs. implicit conversion methods.

Upvotes: 3

Related Questions