3

Possible Duplicate:
Ruby 1.9 Array.to_s behaves differently?

I wonder if anyone can tell me what changed between Ruby 1.8.7 and Ruby 1.9.3. I have an example listed below that behaves totally different in the 2 versions but according to the Ruby docs it doesn't appear anything changed between these versions.

Ruby 1.8

number = '123-45-6789' 
# => "123-45-6789"
number.scan(/[0-9]/)
# => ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
number.scan(/[0-9]/).to_s
# => "123456789"

Ruby 1.9

number = '123-45-6789'
# => "123-45-6789" 
number.scan(/[0-9]/)
# => ["1", "2", "3", "4", "5", "6", "7", "8", "9"]    
number.scan(/[0-9]/).to_s
# => "[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"]"

Not really looking for a different way to do this just curious as to what changed between the two versions.

Community
  • 1
  • 1
mpowmap
  • 651
  • 1
  • 6
  • 11
  • 3
    When a new learner doesn't jump to the same conclusion as you, it hurts our community when you reward that person being intellectually curious with an insult. Rememeber: Matz Is Nice An So We Are Nice (MINASWAN) – Sean Oct 01 '12 at 18:21
  • @sawa Im pretty new to Ruby thus I came here to ask for help. Thanks for going out of your way to make me feel as dumb as possible with your condescending reply. – mpowmap Oct 01 '12 at 18:47

3 Answers3

5

Here's what is actually in Ruby source code:

1.8.7:

rb_ary_to_s(ary)
    VALUE ary;
{
    if (RARRAY(ary)->len == 0) return rb_str_new(0, 0);
    return rb_ary_join(ary, rb_output_fs);
}

In other words, in 1.8.7, to_s calls join.

1.9.3:

rb_ary_inspect(VALUE ary)
{
    if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new2("[]");
    return rb_exec_recursive(inspect_ary, ary, 0);
}

VALUE
rb_ary_to_s(VALUE ary)
{
    return rb_ary_inspect(ary);
}

In other words, in 1.9.3, to_s delegates to inspect.

Note: in future, if you're wondering about a difference you're observing between two versions, you can try taking a look at source code. Easy to pull down from here: https://github.com/ruby/ruby

Not everything is going to be easy to find in there of course, but if you search around for a bit you can often find good leads. In this case, array.c has what you're looking for.

Then you can switch back and forth between versions by issuing git checkout ruby_1_8_7 and git checkout ruby_1_9_3.

manzoid
  • 1,215
  • 8
  • 6
  • ah! I can see why the `1.8` implementation was faster from my microbenchmark. Thanks for sharing! – Igbanam Oct 01 '12 at 19:48
  • github's blame feature leads me to the [commit](https://github.com/ruby/ruby/commit/d1cb9e75d054d06f0a80aeb112b894e82952c6d0), and the comment there leads me to [the discussion](http://translate.google.com/translate?hl=en&sl=ja&u=http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/29520&prev=search) but that leaves me little the wiser as to the reason. – Martin Dorey Jan 07 '15 at 20:53
2

The to_s has been changed to actually do what converting an object to a string should do.

Consider the 1.8 implementation...

  1. When you send to to_s method to the array object, it literally does array_object.join('').to_s. This IMHO does too much.
  2. This implementation also misrepresents the array object. The to_s method mainly goes hand-in-hand with the inspect method (_correct me if I'm wrong because I am working off my head here). And if you should look at the output of the to_s method here, you cannot tell if the object is of the Array, String or Fixnum class.

Enter 1.9 implementation...

  1. The structure of the output clearly shows the object is an array.

That been said, I think this was a UX design decision from the Ruby team ...because the to_s in 1.8 is considerably faster!

Consider this microbenchmark...

OS_X_Terminal $> time ruby -e "(1..1000000).to_a.map(&:to_s).to_s"

| Ruby Version | average runtime |
|    1.9.3     |      1.678      |
|    1.9.2     |      1.817      |
|    1.8.7     |      1.106      |

This is all I have so far. Comments are always welcome (:

Igbanam
  • 5,904
  • 5
  • 44
  • 68
0

It looks like ruby just got smarter about what .to_s does. It used to be dumb and for some reason list all entries in the array side by side. In ruby 1.9 it takes the array and literally turns it in to a string. That is a smarter way of handling .to_s.

weexpectedTHIS
  • 3,358
  • 1
  • 25
  • 30