We recently upgraded a client app from Ruby 1.8.7 to Ruby 1.9.3, just as support for Ruby 1.8.7 was ending. We ran into some "gotchas" while upgrading, so perhaps these will help other developers in the future.
In general, the incompatibilities between Ruby 1.8 and 1.9 are well-known, but we discovered a few lesser-known issues during this upgrade.
1. Array#to_s
In Ruby 1.8, calling to_s on an Array is equivalent to calling join.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
>> [1, 2, 3].to_s | |
=> "123" | |
>> [1, 2, 3].join | |
=> "123" | |
>> [1, 2, 3].inspect | |
=> "[1, 2, 3]" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
irb(main):001:0> [1, 2, 3].to_s | |
=> "[1, 2, 3]" | |
irb(main):002:0> [1, 2, 3].join | |
=> "123" | |
irb(main):003:0> [1, 2, 3].inspect | |
=> "[1, 2, 3]" |
This seems like a minor change, but it is significant. There are many Ruby 1.8 libraries that will display arrays directly to users via to_s, assuming the array will be suitable for display directly to an end-user.
If that code is run against Ruby, 1.9 the displayed array will include both the brackets and commas, usually making it unsuitable for end-user display.
2. Symbol#to_i gone
As of Ruby 1.9.2., symbols are no longer internally represented as integers and Symbol#to_i was removed (thanks to andrewjgrimm for pointing this out). Thus, if you call string_object[:symbol], it will use the symbol's integer representation to reference an element under Ruby 1.8.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Ruby 1.8 | |
>> "hello there"[:symbol] | |
=> nil | |
# Ruby 1.9 | |
>> "hello there"[:symbol] | |
TypeError: can't convert Symbol into Integer |
In Ruby 1.8, you can actually create a hash by putting an list of keys and values directly in the curly braces. In Ruby 1.9, that doesn't work.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Ruby 1.8 | |
>> {:a, 100, :b, 200, :c, 300} | |
=> {:b=>200, :a=>100, :c=>300} | |
# Ruby 1.9 | |
>> {:a, 100, :b, 200, :c, 300} | |
SyntaxError: (irb):1: syntax error, unexpected ',', expecting tASSOC | |
Backwards compatibility in languages is important, especially when building enterprise applications. Even if a seemingly-arbitrary change looks like a net win for program correctness, it can cause problems in legacy software.
For example, consider the following code:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
countries = method_that_returns_a_hash | |
if countries[:canada] | |
another_method_call | |
end |
What other obscure incompatibilities have you encountered while upgrading legacy software?
2 comments:
In Ruby 1.8, Symbols had a #to_int method.
>> :foo.to_int
=> 15113
>> x = "a" * 15000 + "b" * 1000 ; nil
=> nil
>> x[:foo]
=> 98
>> x[:foo,1]
=> "b"
By contrast, in Ruby 1.9, Symbols don't have :to_int (or :to_i).
Thanks much for pointing that out, andrewjgrimm. I updated this post and gave you credit.
Post a Comment