Justification for Array#join behaviour?

What is the justification for [1,2,[3,4]].join(‘,’) being ‘1,2,3,4’
instead of ‘1,2,34’? According to ruby-doc.org join “Returns a string
created by converting each element of the array to a string, separated
by sep.”. Why should an element be recursively joined if it’s also an
array?

Farrel

I second that.

On Feb 14, 12:52 am, “Farrel L.” [email protected] wrote:

What is the justification for [1,2,[3,4]].join(‘,’) being ‘1,2,3,4’
instead of ‘1,2,34’? According to ruby-doc.org join “Returns a string
created by converting each element of the array to a string, separated
by sep.”. Why should an element be recursively joined if it’s also an
array?

What’s the justification for it NOT doing that? (Just because the docs
say so?)

I suspect that it’s more like the join method #flatten s the array
before joining, instead of recursing. But my C isn’t good enough to
tell what rb_ary_join is really doing inside.

I’m not sure I can think of a real use case for either scenario. The
only one I can make up is where you want to override Array#to_s, where
you’d want the last line below…

irb(main):001:0> class Foo; def to_s;“SSS”;end; def inspect;“III”;end;
end
=> nil
irb(main):002:0> a = [ 1, 2, Foo.new, [ 3, Foo.new, [ 4, 5 ] ] ]
=> [1, 2, III, [3, III, [4, 5]]]
irb(main):003:0> a.join( ‘,’ )
=> “1,2,SSS,3,SSS,4,5”
irb(main):005:0> class Array; def to_s; “”; end; end
=> nil
irb(main):006:0> a.to_s
=> “”
irb(main):008:0> a.join( ‘,’ )
=> “1,2,SSS,3,SSS,4,5”

…to return “1,2,SSS,” instead.

Hrm…yeah, I think I’d prefer that simpler and more powerful
implementation. Of course, if you really wanted it, you could change
it yourself:

irb(main):009:0> class Array
irb(main):010:1> def join( sep=‘’ )
irb(main):011:2> output = “”
irb(main):012:2> each_with_index do |v,i|
irb(main):013:3* output << v.to_s
irb(main):014:3> output << sep unless i == (self.length-1)
irb(main):015:3> end
irb(main):016:2> output
irb(main):017:2> end
irb(main):018:1> end
=> nil
irb(main):019:0> a.join( ‘,’ )
=> “1,2,SSS,”

…but (barring someone else’s good explanation) I’d rather see the
implementation changed to match the documentation (and force you to
use a.flatten.join(‘,’) if that’s what you want) than the reverse.

On 14/02/07, Bertram S. [email protected] wrote:

http://www.bertram-scharpf.de

I did some experimentation and it seems that the decision might not
be that half bad. Take for instance a deeply nested array
[1,2,[3,4[5,6]]]. Currently calling join produces “1,2,3,4,5,6”.
Whereas if we used the non-recursive join we’d get “1,2,3456” which
actually looks a bit worse. I think it would be better if the
documentation was amended to reflect that nested arrays will be
flattened.

Farrel

Hi,

Am Mittwoch, 14. Feb 2007, 16:52:00 +0900 schrieb Farrel L.:

What is the justification for [1,2,[3,4]].join(‘,’) being ‘1,2,3,4’
instead of ‘1,2,34’? According to ruby-doc.org join “Returns a string
created by converting each element of the array to a string, separated
by sep.”. Why should an element be recursively joined if it’s also an
array?

You would have to ask for the objects type:

class Array
def deep_join sep
map { |x|
case x
when Array then x.deep_join sep
else x.to_s
end
}.join sep
end
end

I don’t look at this as a smart programming style actually.

The object-oriented approach is to redefine `to_s’.

Bertram

Farrel L. schrieb:

What is the justification for [1,2,[3,4]].join(‘,’) being ‘1,2,3,4’
instead of ‘1,2,34’? According to ruby-doc.org join “Returns a string
created by converting each element of the array to a string, separated
by sep.”. Why should an element be recursively joined if it’s also an
array?

Farrel

It is easy to come to the required result by

irb(main):001:0> [1,2,[3,4]].map{|e|e.to_s}.join(‘,’)
=> “1,2,34”

…but I think this should be the “natural” way of handling it by
“join”.
Implicit recursion (or “flatten” in this special case) can be confusing
in some
situation.

Wolfgang Nádasi-Donner

On 2/15/07, Bertram S. [email protected] wrote:

end

I don’t look at this as a smart programming style actually.

The object-oriented approach is to redefine `to_s’.

Or

class Object
def join
to_s
end
end

module Enumerable
def join
“[” + inject {|a, e| a.join + ", " + e.join} + “]”
end
end

class Array
def join
super
end
end

class String
def join
self
end
end

puts [1, 2, 3, [4, 5, [6, 7], 8]].join

martin

Hi,

Am Donnerstag, 15. Feb 2007, 16:14:17 +0900 schrieb Martin DeMello:

On 2/15/07, Bertram S. [email protected] wrote:

The object-oriented approach is to redefine `to_s’.

Or

[…]
puts [1, 2, 3, [4, 5, [6, 7], 8]].join
[1, 2, 3, [4, 5, [6, 7], 8]]

Ah, yes. It’s the open and close delimiters ([]) what is
getting lost by the OP’s proposal. I should have seen that
right away.

Bertram

On Feb 14, 2007, at 2:52 AM, Farrel L. wrote:

What is the justification for [1,2,[3,4]].join(‘,’) being ‘1,2,3,4’
instead of ‘1,2,34’? According to ruby-doc.org join “Returns a string
created by converting each element of the array to a string, separated
by sep.”. Why should an element be recursively joined if it’s also an
array?

Be aware that Array#to_s has changed in Ruby 1.9

$ irb-1.9
irb(main):001:0> a = [1,2,[3,4]]
=> [1, 2, [3, 4]]
irb(main):002:0> a.to_s
=> “[1, 2, [3, 4]]”
irb(main):003:0> a.join
=> “1234”
irb(main):004:0>

The issue is that Array#to_s defers to Array#inspect in 1.9 instead
of simply concatenating the results of #to_s on all the elements.

I didn’t expect this change either and matz pointed me to Array#join

Check out this thread: ruby-talk:220698

Gary W.