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 ruby language specification
- the rubyspec project
- the yarv testsuite
- the ruby programming language book matz , david flanagan
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 }sameh = { }; 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
Post a Comment