Justification for Array#join behaviour?

F

Farrel Lifson

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
 
P

Phrogz

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; "<hidden>"; end; end
=> nil
irb(main):006:0> a.to_s
=> "<hidden>"
irb(main):008:0> a.join( ',' )
=> "1,2,SSS,3,SSS,4,5"

....to return "1,2,SSS,<hidden>" 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,<hidden>"

....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.
 
W

Wolfgang Nádasi-Donner

Farrel said:
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
 
B

Bertram Scharpf

Hi,

Am Mittwoch, 14. Feb 2007, 16:52:00 +0900 schrieb Farrel Lifson:
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
 
F

Farrel Lifson

Hi,

Am Mittwoch, 14. Feb 2007, 16:52:00 +0900 schrieb Farrel Lifson:
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

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
 
G

Gary Wright

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 Wright
 
M

Martin DeMello

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'.

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
 
B

Bertram Scharpf

Hi,

Am Donnerstag, 15. Feb 2007, 16:14:17 +0900 schrieb Martin DeMello:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top