adampetrie
adampetrie

Reputation: 1150

`Hash.[]` in Ruby in 1.9 and 2.0

I'm upgrading an app from Ruby 1.9.3 to 2.0.0 and I've come across the following:

1.9.3-p545 :001 > Hash[[[], 0]]
# => {}

vs.

2.0.0-p643 :001 > Hash[[[], 0]]
# ArgumentError: invalid number of elements (0 for 1..2)
# :1:in `[]'

I have not been able to find an explanation in the docs or the changelog but I feel like it should be obvious. Can someone explain what changed?

Upvotes: 1

Views: 233

Answers (1)

Dave Schweisguth
Dave Schweisguth

Reputation: 37627

I couldn't find any documentation either, but it seems clear that Ruby changed from quietly discarding bad data in 1.9 to raising an error about it in 2.0.

The relevant part of the documentation didn't change from 1.9 to 2.0: if Hash[] gets a single argument which is an array, that array is expected to be an array of [key, value] pairs, and is converted to a Hash accordingly. (In 1.9 Hash[] was the only way to do that conversion; in 2.0 you can call .to_h on an array.)

The first element in [[], 0] isn't a [key, value] pair, and neither is the second element.

  • Ruby 1.9 quietly discards both elements, resulting in an empty hash. Ruby 1.9 does convert the valid elements in an array with both valid and invalid elements:

    Hash[[[], [:a, :b], 0]]] == {:a=>:b}
    
  • Instead of quietly discarding the invalid elements, Ruby 2 (both 2.0.0 and the recent releases of 2.1 and 2.2 I have handy) reports the first invalid element with the ArgumentError you cite.

Interestingly, the ArgumentError tips us off to an otherwise undocumented feature: in both 1.9 and 2.*, Hash[] converts one-element arrays in a single array argument to hash keys whose value is nil. And you can intermix one- and two-element arrays. This feature must be for backward compatibility, because 2.*'s Array#to_h only accepts two-element arrays.

Upvotes: 1

Related Questions