Array#join using to_a if defined

B

Benoit Daloze

[Note: parts of this message were removed to make it a legal post.]

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

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

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"

I got "to_s to_s" in 1.8.6, 1.8.7, and 1.9.1
 
B

Benoit Daloze

[Note: parts of this message were removed to make it a legal post.]

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"

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>]
 
R

Robert Klemme

2010/3/1 Benoit Daloze said:
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
 
C

Caleb Clausen

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

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,153
Members
46,701
Latest member
XavierQ83

Latest Threads

Top