# KaraokeSong#to\_s example in book

**URL:** <https://www.ruby-forum.com/t/karaokesong-to-s-example-in-book/166583>\
**Category:** Ruby\
**Created:** [April 27, 2009, 4:36pm UTC](https://www.ruby-forum.com/t/karaokesong-to-s-example-in-book/166583 "2009-04-27T16:36:15Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Clifford\_L](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/ecc23a/32.png) [@Clifford\_L](https://www.ruby-forum.com/u/Clifford_L)\
**Post date:** [April 27, 2009, 4:36pm UTC](https://www.ruby-forum.com/t/karaokesong-to-s-example-in-book/166583/1 "2009-04-27T16:36:15Z")

</div>

Hi,  
I’m reading the online eBook of Programming Ruby, it’s an excellent  
resource for learning Ruby.  
I am having some trouble understanding the KaraokeSong#to\_s example.

Quoting the text:  
"  
class KaraokeSong

# …

def to\_s  
“KS: #{@name}–#{@artist} (#{@duration}) [#{@lyrics}]”  
end  
end  
aSong = KaraokeSong.new(“My Way”, “Sinatra”, 225, “And now, the…”)  
aSong.to\_s » “KS: My Way–Sinatra (225) [And now, the…]”

We’re correctly displaying the value of the |@lyrics| instance variable.  
To do this, the subclass directly accesses the instance variables of its  
ancestors. So why is this a bad way to implement |to\_s|? The answer has  
to do with good programming style (and something called /decoupling/).  
By poking around in our parent’s internal state, we’re tying ourselves  
tightly to its implementation. Say we decided to change |Song| to store  
the duration in milliseconds. Suddenly, |KaraokeSong| would start  
reporting ridiculous values. The idea of a karaoke version of ``My Way’’  
that lasts for 3750 minutes is just too frightening to consider."

What does it mean by “the subclass directly accesses the instance  
variables of its ancestors”? The Song class does not have the @lyrics  
instance variable. And are @name, @artist, and @duration not instance  
variables for the KaraokeSong class, so they have nothing to do with the  
instance variables with the same name for the Song class? Even if I  
change Song to store the duration in milliseconds, would not KaraokeSong  
still store in minutes, because when I create a new KaraokeSong object,  
I pass it the duration argument in minutes?

Perhaps an example of what could go wrong would help.

Dave T. kindly replied with the following:  
“Classes don’t have instance variables: instances do. But classes  
contain the code that uses instance variables. So, in this case, the  
code that “knows about” @name (for example) is in the Song class. The  
subclass should not assume this internal implementation. Instead, it  
should use the interface provided by the Song class, in this case using  
its to\_s method.”

But I am still confused. OK, so the code that “knows about” @name, etc.  
is in the Song class, but doesn’t the KaraokeSong class also know about  
these instance variables? Since it super’d the initialize method?

Thanks to clear this up.

Regards,  
Clifford L.

---

<div class="post-metadata">

**Author:** ![Clifford\_L](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/ecc23a/32.png) [@Clifford\_L](https://www.ruby-forum.com/u/Clifford_L)\
**Post date:** [April 27, 2009, 4:50pm UTC](https://www.ruby-forum.com/t/karaokesong-to-s-example-in-book/166583/2 "2009-04-27T16:50:59Z")

</div>

On Mon, Apr 27, 2009 at 4:35 PM, Clifford L. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> ```
> "KS: #{@name}--#{@artist} (#{@duration}) [#{@lyrics}]"
> 
> ```
> 
> to its implementation. Say we decided to change |Song| to store the duration  
> minutes, because when I create a new KaraokeSong object, I pass it the
> 
> But I am still confused. OK, so the code that “knows about” @name, etc. is  
> in the Song class, but doesn’t the KaraokeSong class also know about these  
> instance variables? Since it super’d the initialize method?

No, because the public interface to create an instance of Song states  
that you have to pass  
the duration in minutes, but you don’t know what calculations the Song  
initialize method  
might do to actually store the duration. An example:

class Song  
def initialize name, artist, duration, lyrics  
@name = name  
@artist = artist  
@duration = duration \* 60000 # store the duration in ms  
@lyrics = lyrics  
end

def duration  
@duration / 60000  
end  
end

if you blindly do:

class KaraokeSong \< Song  
def initialize name, artist, duration, lyrics  
super  
end

def to\_s  
“#{@name} - #{@artist} (#{@duration} minutes). #{@lyrics}”  
end  
end

Then you will be reporting wrong values for the duration. Instead you  
should use the accessor that Song provides to access the duration in  
minutes. The @duration is what the quoted authors say it’s Song’s  
internal state, Song’s internal implementation.  
By calling super you are delegating the management of the duration to  
Song’s implementation, of which you shouldn’t use its internal  
structures for more decoupling.

Hope this clears it up a little bit.

Jesus.

---

<div class="post-metadata">

**Author:** ![Clifford\_L](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/ecc23a/32.png) [@Clifford\_L](https://www.ruby-forum.com/u/Clifford_L)\
**Post date:** [April 28, 2009, 12:41am UTC](https://www.ruby-forum.com/t/karaokesong-to-s-example-in-book/166583/3 "2009-04-28T00:41:42Z")

</div>

Jesús Gabriel y Galán wrote:

> > ```
> > def to_s
> > 
> > ```
> > 
> > poking around in our parent’s internal state, we’re tying ourselves tightly  
> > store the duration in milliseconds, would not KaraokeSong still store in  
> > interface provided by the Song class, in this case using its to\_s method."
> 
> end  
> “#{@name} - #{@artist} (#{@duration} minutes). #{@lyrics}”
> 
> Hope this clears it up a little bit.
> 
> Jesus.

Hi,  
Thanks for the reply.  
I could understand if that was the case, but that’s not the case in the  
example in the book. For reference, I am reading:

[http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut\_classes.html](http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_classes.html)

If I understand the examples correctly, the example code they have used  
is:

class Song  
def initialize(name, artist, duration)  
@name = name  
@artist = artist  
@duration = duration  
end

def to\_s  
“Song: #{@name}–#{@artist} (#{@duration})”  
end  
end

class KaraokeSong \< Song  
def initialize(name, artist, duration, lyrics)  
super(name, artist, duration)  
@lyrics = lyrics  
end

def to\_s  
“KS: #{@name}–#{@artist} (#{@duration}) [#{@lyrics}]”  
end  
end

It says that you should not implement the class KaraokeSong’s to\_s  
method as above, but rather, you should do it this way:

def to\_s  
super + " [#{@lyrics}]"  
end

The reason being: "So why is this a bad way to implement to\_s?

The answer has to do with good programming style (and something called  
decoupling). By poking around in our parent’s internal state, we’re  
tying ourselves tightly to its implementation. Say we decided to change  
Song to store the duration in milliseconds. Suddenly, KaraokeSong would  
start reporting ridiculous values. The idea of a karaoke version of ``My  
Way’’ that lasts for 3750 minutes is just too frightening to consider.

We get around this problem by having each class handle its own internal  
state. When KaraokeSong#to\_s is called, we’ll have it call its parent’s  
to\_s method to get the song details."

This is what I don’t understand.

Thanks.

Cliff

---

<div class="post-metadata">

**Author:** ![Clifford\_L](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/ecc23a/32.png) [@Clifford\_L](https://www.ruby-forum.com/u/Clifford_L)\
**Post date:** [April 28, 2009, 10:21am UTC](https://www.ruby-forum.com/t/karaokesong-to-s-example-in-book/166583/4 "2009-04-28T10:21:03Z")

</div>

Jesús Gabriel y Galán wrote:

> functionality. Then, if you have used the internal implementation, you  
> have a problem.
> 
> Hope this helps.
> 
> Jesus.

I think I’ve got it.

Thanks.

---

<div class="post-metadata">

**Author:** ![Clifford\_L](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/ecc23a/32.png) [@Clifford\_L](https://www.ruby-forum.com/u/Clifford_L)\
**Post date:** [April 28, 2009, 9:58am UTC](https://www.ruby-forum.com/t/karaokesong-to-s-example-in-book/166583/5 "2009-04-28T09:58:45Z")

</div>

On Tue, Apr 28, 2009 at 12:40 AM, Clifford L. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> I could understand if that was the case, but that’s not the case in the  
> example in the book.

The point is that if you limit yourself to using the public interface  
of a class,  
you protect yourself against changes in the internal implementation.

Say that tomorrow, the implementer of the Song class receives a new  
requirement,  
and he decides to store the duration in ms, to more easily implement the  
new  
functionality. Then, if you have used the internal implementation, you  
have a problem.

Hope this helps.

Jesus.
