loops - Is order of a Ruby hash literal guaranteed? -


ruby, since v1.9, supports deterministic order when looping through hash; entries added first returned first.

does apply literals, ie { a: 1, b: 2 } yield before b?

i did quick experiment ruby 2.1 (mri) , in fact consistent, extent guaranteed language work on ruby implementations?

there couple of locations could specified, i.e. couple of things considered "the ruby language specification":

the iso spec doesn't hash ordering: written in such way existing ruby implementations automatically compliant it, without having change, i.e. written descriptive of current ruby implementations, not prescriptive. @ time spec written, implementations included mri, yarv, rubinius, jruby, ironruby, maglev, macruby, xruby, ruby.net, cardinal, tinyrb, rubygolightly, smallruby, blueruby, , others. of particular interest mri (which only implements 1.8) , yarv (which only implements 1.9 (at time)), means spec can specify behavior common 1.8 , 1.9, hash ordering not.

the rubyspec project abandoned developers out of frustration ruby-core developers , yarv developers never recognized it. does, however, (implicitly) specify hash literals ordered left-to-right:

new_hash(1 => 2, 4 => 8, 2 => 4).keys.should == [1, 4, 2] 

that's spec hash#keys, however, other specs test hash#values has same order hash#keys, hash#each_value , hash#each_key has same order those, , hash#each_pair , hash#each have same order well.

i couldn't find in the yarv testsuite specifies ordering preserved. in fact, couldn't find at all ordering in testsuite, quite opposite: tests go great length avoid depending on ordering!

the flanagan/matz book kinda-sorta implicitly specifies hash literal ordering in section 9.5.3.6 hash iterators. first, uses same formulation docs:

in ruby 1.9, however, hash elements iterated in insertion order, […]

but goes on:

[…], , order shown in following examples:

and in examples, actually uses literal:

h = { :a=>1, :b=>2, :c=>3 }  # each() iterator iterates [key,value] pairs h.each {|pair| print pair }    # prints "[:a, 1][:b, 2][:c, 3]"  # works 2 block arguments h.each |key, value|                   print "#{key}:#{value} "     # prints "a:1 b:2 c:3"  end  # iterate on keys or values or both h.each_key {|k| print k }      # prints "abc" h.each_value {|v| print v }    # prints "123" h.each_pair {|k,v| print k,v } # prints "a1b2c3". each 

in his comment, @mu short mentioned that

h = { a: 1, b: 2 } same h = { }; h[:a] = 1; h[:b] = 2

and in another comment that

nothing else make sense

unfortunately, not true:

module hashasetwithlogging   def []=(key, value)     puts "[]= called [#{key.inspect}] = #{value.inspect}"     super   end end  class hash   prepend hashasetwithlogging end  h = { a: 1, b: 2 } # prints nothing  h = { }; h[:a] = 1; h[:b] = 2 # []= called [:a] = 1 # []= called [:b] = 2 

so, depending on how interpret line book , depending on how "specification-ish" judge book, yes, ordering of literals is guaranteed.


Comments