Reputation: 323
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
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
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