# Needing help with which to\_s gets called

**URL:** <https://www.ruby-forum.com/t/needing-help-with-which-to-s-gets-called/144661>\
**Category:** Ruby\
**Created:** [July 31, 2008, 10:19pm UTC](https://www.ruby-forum.com/t/needing-help-with-which-to-s-gets-called/144661 "2008-07-31T22:19:27Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![princenamor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/c0e974/32.png) [@princenamor](https://www.ruby-forum.com/u/princenamor)\
**Post date:** [July 31, 2008, 10:19pm UTC](https://www.ruby-forum.com/t/needing-help-with-which-to-s-gets-called/144661/1 "2008-07-31T22:19:27Z")

</div>

I’m a beginner learning Ruby and I’ve hit something which I can’t find  
an explanation for in my text books.

If I run the following code:

class Able \< Array

# def initialize(contents)

# @contents = Array.new(contents)

# end

def to\_s  
“[Able: #{self.join(”, “)}]”  
end  
end

class Baker  
def initialize(contents)  
@contents = Array.new(contents)  
end

def \<\<(item)  
@contents \<\< item  
end

def to\_s  
“[Baker: #{@contents.join(”, “)}]”  
end  
end

item = Baker.new([“a”, “b”])  
item \<\< Able.new([“c”, “d”])  
item \<\< “e”  
puts item

I get the following output:

[Baker: a, b, c, d, e]

Clearly the to\_s method in my Able class is not being called. If  
however I change the definition of Able to:

class Able  
def initialize(contents)  
@contents = Array.new(contents)  
end

def to\_s  
“[Able: #{@contents.join(”, “)}]”  
end  
end

(Note that it no longer inherits from Array and instead contains an  
array as an instance variable.)

I now get this output (which is what I wanted in the first place).

[Baker: a, b, [Able: c, d], e]

Why when Able is a sub-class of Array does my to\_s method get ignored?

TIA,  
Joh

P.S. I tried to read the FAQ as instructed first but the link given for  
it gives a “Not found” error.

---

<div class="post-metadata">

**Author:** ![princenamor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/c0e974/32.png) [@princenamor](https://www.ruby-forum.com/u/princenamor)\
**Post date:** [July 31, 2008, 10:24pm UTC](https://www.ruby-forum.com/t/needing-help-with-which-to-s-gets-called/144661/2 "2008-07-31T22:24:48Z")

</div>

John W. wrote:

> Why when Able is a sub-class of Array does my to\_s method get ignored?

Because puts special cases arrays, not calling to\_s on them at all.  
If you compare puts [1,2,3] to puts [1,2,3].to\_s you will see  
that this is the case (puts [1,2,3] is just like puts 1,2,3 printing  
each number on its own line instead of having it all in one line like  
you get with to\_s.

HTH,  
Sebastian

---

<div class="post-metadata">

**Author:** ![princenamor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/c0e974/32.png) [@princenamor](https://www.ruby-forum.com/u/princenamor)\
**Post date:** [July 31, 2008, 10:32pm UTC](https://www.ruby-forum.com/t/needing-help-with-which-to-s-gets-called/144661/3 "2008-07-31T22:32:06Z")

</div>

Sebastian H. wrote:

> John W. wrote:
> 
> > Why when Able is a sub-class of Array does my to\_s method get ignored?
> 
> Because puts special cases arrays, not calling to\_s on them at all.  
> If you compare puts [1,2,3] to puts [1,2,3].to\_s you will see  
> that this is the case (puts [1,2,3] is just like puts 1,2,3 printing  
> each number on its own line instead of having it all in one line like  
> you get with to\_s.

Thanks for that. There certainly seems to be some sort of  
special-casing going on, but it’s more widespread than just puts.

I tried the test case which you suggested and see exactly what you said.  
However I also went back to my original code and changed the “puts” line  
from:

puts item

to:

output = item.to\_s  
puts output

and I still get the same oddity so it’s clearly not just puts doing it.

Do you have a reference where I can read up more on this?

TIA,  
John

---

<div class="post-metadata">

**Author:** ![princenamor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/c0e974/32.png) [@princenamor](https://www.ruby-forum.com/u/princenamor)\
**Post date:** [July 31, 2008, 10:36pm UTC](https://www.ruby-forum.com/t/needing-help-with-which-to-s-gets-called/144661/4 "2008-07-31T22:36:31Z")

</div>

On Thu, Jul 31, 2008 at 2:31 PM, John W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> Thanks for that. There certainly seems to be some sort of  
> output = item.to\_s

output is an instance of Baker so Ruby will invoke Baker’s to\_s method.

–  
“Hey brother Christian with your high and mighty errand, Your actions  
speak  
so loud, I can’t hear a word you’re saying.”

-Greg Graffin (Bad Religion)

---

<div class="post-metadata">

**Author:** ![princenamor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/c0e974/32.png) [@princenamor](https://www.ruby-forum.com/u/princenamor)\
**Post date:** [July 31, 2008, 10:44pm UTC](https://www.ruby-forum.com/t/needing-help-with-which-to-s-gets-called/144661/5 "2008-07-31T22:44:43Z")

</div>

John W. wrote:

> Thanks for that. Â There certainly seems to be some sort of  
> special-casing going on, but it’s more widespread than just puts.

You’re right. join special cases arrays as well, joining nested arrays  
as well  
instead of to\_sing them (that or it just calls flatten on the array  
before  
starting it’s work).

HTH,  
Sebastian

---

<div class="post-metadata">

**Author:** ![princenamor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/c0e974/32.png) [@princenamor](https://www.ruby-forum.com/u/princenamor)\
**Post date:** [July 31, 2008, 10:41pm UTC](https://www.ruby-forum.com/t/needing-help-with-which-to-s-gets-called/144661/6 "2008-07-31T22:41:11Z")

</div>

On Thu, Jul 31, 2008 at 2:35 PM, Glen H. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> > > you get with to\_s.  
> > > to:  
> > > –

Actually now that I think about it a little more it appears that in the  
first case something a little odd is happening in that Ruby is just  
treating  
the Able data as a normal array but as soon as you assign the data to an  
instance variable is adds an instance of Able to the array rather than  
just  
passing the array values through.

–  
“Hey brother Christian with your high and mighty errand, Your actions  
speak  
so loud, I can’t hear a word you’re saying.”

-Greg Graffin (Bad Religion)

---

<div class="post-metadata">

**Author:** ![princenamor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/c0e974/32.png) [@princenamor](https://www.ruby-forum.com/u/princenamor)\
**Post date:** [July 31, 2008, 10:51pm UTC](https://www.ruby-forum.com/t/needing-help-with-which-to-s-gets-called/144661/7 "2008-07-31T22:51:46Z")

</div>

On Thu, Jul 31, 2008 at 4:41 PM, Sebastian H.  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> John W. wrote:
> 
> > Thanks for that. There certainly seems to be some sort of  
> > special-casing going on, but it’s more widespread than just puts.
> 
> You’re right. join special cases arrays as well, joining nested arrays as well  
> instead of to\_sing them (that or it just calls flatten on the array before  
> starting it’s work).

I guess this is an example of core class special cases that I was  
worried about in an earlier thread today.

I really don’t think it’s a good practice to subclass core classes  
unless you are only adding new behaviour.  
Wrapping and delegating is much more predictable.

That having been said, the problem goes away if you first explicitly  
map using to\_s before the join(), but this is an indication of the  
kind of hacks subclassing core objects like Array will force upon you  
:-/

def to\_s  
“[Baker: #{@contents.map { |e| e.to\_s }.join(”, “)}]”  
end

---

<div class="post-metadata">

**Author:** ![princenamor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/c0e974/32.png) [@princenamor](https://www.ruby-forum.com/u/princenamor)\
**Post date:** [July 31, 2008, 11:18pm UTC](https://www.ruby-forum.com/t/needing-help-with-which-to-s-gets-called/144661/8 "2008-07-31T23:18:31Z")

</div>

Thanks to all for some very useful pointers.

On Thu, Jul 31, 2008 at 4:41 PM, Sebastian H.  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:  
[snip]

> You’re right. join special cases arrays as well, joining nested arrays as well  
> instead of to\_sing them (that or it just calls flatten on the array before  
> starting it’s work).

That certainly seems to be the case, as witnessed by the following  
snippet.

a = [“a”, “b”, “c”]  
b = [“d”, “e”, “f”]  
c = Array.new  
c \<\< a  
c \<\< b  
puts “Size of c is #{c.size}”  
puts c.join(", ")

which produces:

Size of c is 2  
a, b, c, d, e, f

It looks very much like join will flatten anything which it thinks it  
can.

Gregory B. wrote:

> I guess this is an example of core class special cases that I was  
> worried about in an earlier thread today.
> 
> I really don’t think it’s a good practice to subclass core classes  
> unless you are only adding new behaviour.  
> Wrapping and delegating is much more predictable.

Thank you - I’ll take note of that. My original problem was that I have  
a structure involving nested arrays and I wanted them to print out with  
the nesting apparent. Sub-classing Array seemed the obvious way to do  
it, but perhaps not.

> That having been said, the problem goes away if you first explicitly  
> map using to\_s before the join(), but this is an indication of the  
> kind of hacks subclassing core objects like Array will force upon you  
> :-/
> 
> def to\_s  
> “[Baker: #{@contents.map { |e| e.to\_s }.join(”, “)}]”  
> end

Adding to the snippet above:

puts c.map { |e| e.to\_s }.join(", ")

Produces:

abc, def

So I now have a choice of two ways to do it.

Cheers,  
John
