# Array#join using to\_a if defined

**URL:** <https://www.ruby-forum.com/t/array-join-using-to-a-if-defined/184314>\
**Category:** Ruby\
**Created:** [February 28, 2010, 7:53pm UTC](https://www.ruby-forum.com/t/array-join-using-to-a-if-defined/184314 "2010-02-28T19:53:38Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![benoitdinocourt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/87869e/32.png) [@benoitdinocourt](https://www.ruby-forum.com/u/benoitdinocourt)\
**Post date:** [February 28, 2010, 7:53pm UTC](https://www.ruby-forum.com/t/array-join-using-to-a-if-defined/184314/1 "2010-02-28T19:53:38Z")

</div>

Hi,

I got recently an unexpected result using Array#join.

In my thoughts, Array#join is sth like adding the separator between  
every  
element#to\_s.

That is what seems to happen when there is no any #to\_a method defined  
in an  
element:

For example,  
class N \< Struct.new(:n)  
def to\_s  
‘to\_s’  
end  
end

[N.new(2), N.new(3)].join(’ ') #=\> “2 3” and not “to\_s to\_s”

This is due to Struct::new that defines #to\_a that return an Array of  
instance variables (here :n).  
That’s quite annoying, because you would expect when you’re defining  
to\_s to  
be the only usual String representation.  
The only way to edit that behavior without changing Array#join, is to  
“undef\_method :to\_a”, not very nice …  
or to use ary.map(&:to\_s).join, very redundant.

Shouldn’t Array#join looks like:  
class Array  
def join(sep = $,)  
sep = ‘’ if sep.nil?  
s = “”  
self.each\_with\_index { |e, i|  
s \<\< e.to\_s  
s \<\< sep unless i == size-1  
}  
s  
end  
end

Why is it this ‘look’ to element#to\_a ? is that really interesting?  
when?  
Maybe when you use [[1],[2,3]].join #=\> “123” ? Then we should look for  
#to\_ary, not #to\_a

Regards,  
B.D.

---

<div class="post-metadata">

**Author:** ![benoitdinocourt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/87869e/32.png) [@benoitdinocourt](https://www.ruby-forum.com/u/benoitdinocourt)\
**Post date:** [March 1, 2010, 4:25am UTC](https://www.ruby-forum.com/t/array-join-using-to-a-if-defined/184314/2 "2010-03-01T04:25:41Z")

</div>

On Sun, Feb 28, 2010 at 12:53 PM, Benoit D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> For example,  
> class N \< Struct.new(:n)  
> def to\_s  
> ‘to\_s’  
> end  
> end
> 
> [N.new(2), N.new(3)].join(’ ') #=\> “2 3” and not “to\_s to\_s”

I got “to\_s to\_s” in 1.8.6, 1.8.7, and 1.9.1

---

<div class="post-metadata">

**Author:** ![benoitdinocourt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/87869e/32.png) [@benoitdinocourt](https://www.ruby-forum.com/u/benoitdinocourt)\
**Post date:** [March 1, 2010, 2:34pm UTC](https://www.ruby-forum.com/t/array-join-using-to-a-if-defined/184314/3 "2010-03-01T14:34:22Z")

</div>

On 1 March 2010 04:25, Josh C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > That is what seems to happen when there is no any #to\_a method defined in  
> > [N.new(2), N.new(3)].join(’ ') #=\> “2 3” and not “to\_s to\_s”
> 
> I got “to\_s to\_s” in 1.8.6, 1.8.7, and 1.9.1

Me:  
irb for ruby-1.9.2-r26764

> class N \< Struct.new(:n)  
> def to\_s  
> ‘to\_s’  
> end  
> end  
> =\> nil  
> [N.new(2), N.new(3)].join(’ ')  
> =\> “2 3”

irb for ruby-1.8.7-p249

> class N \< Struct.new(:n)  
> def to\_s  
> ‘to\_s’  
> end  
> end  
> =\> nil  
> [N.new(2), N.new(3)].join(’ ')  
> =\> “to\_s to\_s”

So this would be only 1.9.2 behavior, but why on world this changed? It  
has  
such bad side-effect in this case.

* * *

Also, while playing with Array, using Array#&, I saw it look on #eql?  
and  
#hash methods. These two methods are relative to Hash usually, I didn’t  
expect methods of Array to depends of them.  
A surprising result to me:

irb for ruby-1.9.2-r26764

> [1,2]&[2]  
> =\> [2]  
> class N  
> def initialize(n)  
> @n = n  
> end  
> attr\_reader :n  
> def == o  
> @n == o.n  
> end  
> end  
> =\> nil  
> [N.new(1),N.new(2)]&[N.new(2)]  
> =\> [] # instead of [#\<N:… @n=2\>]

---

<div class="post-metadata">

**Author:** ![benoitdinocourt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/87869e/32.png) [@benoitdinocourt](https://www.ruby-forum.com/u/benoitdinocourt)\
**Post date:** [March 2, 2010, 8:39pm UTC](https://www.ruby-forum.com/t/array-join-using-to-a-if-defined/184314/4 "2010-03-02T20:39:03Z")

</div>

On 3/1/10, Benoit D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Also, while playing with Array, using Array#&, I saw it look on #eql? and  
> #hash methods. These two methods are relative to Hash usually, I didn’t  
> expect methods of Array to depends of them.

It’s because the efficient (O(1)) implementation of Array#& requires  
creating a temporary hash (or 2?) internally. However, this would seem  
to be an internal detail and callers should not have to know about it,  
as your example (quoted below) demonstrates.

---

<div class="post-metadata">

**Author:** ![benoitdinocourt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/87869e/32.png) [@benoitdinocourt](https://www.ruby-forum.com/u/benoitdinocourt)\
**Post date:** [March 1, 2010, 3:56pm UTC](https://www.ruby-forum.com/t/array-join-using-to-a-if-defined/184314/5 "2010-03-01T15:56:54Z")

</div>

2010/3/1 Benoit D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> So this would be only 1.9.2 behavior, but why on world this changed? It has  
> such bad side-effect in this case.

Maybe #flatten’s functionality was extended to also include objects  
that implement to\_a because to\_a has been removed from Object in  
1.9…

> Also, while playing with Array, using Array#&, I saw it look on #eql? and  
> #hash methods. These two methods are relative to Hash usually, I didn’t  
> expect methods of Array to depends of them.

Learn something new every day. 😉

Kind regards

robert
