Knight of Ni
Knight of Ni

Reputation: 1830

Ruby: rules for implicit hashes

Why second output shows me only one element of Array? Is it still Array or Hash already?

def printArray(arr)
    arr.each { | j |
        k, v = j.first
        printf("%s %s %s \n", k, v, j)
    }
end

print "Array 1\n"
printArray( [
                {kk: { 'k1' => 'v1' }},
                {kk: { 'k2' => 'v2' }},
                {kk: { 'k3' => 'v3' }},
            ])


print "Array 2\n"
printArray( [
                kk: { 'k1' => 'v1' },
                kk: { 'k2' => 'v2' },
                kk: { 'k3' => 'v3' },
            ])

exit

# Output:
#
# Array 1
# kk {"k1"=>"v1"} {:kk=>{"k1"=>"v1"}} 
# kk {"k2"=>"v2"} {:kk=>{"k2"=>"v2"}} 
# kk {"k3"=>"v3"} {:kk=>{"k3"=>"v3"}} 
# Array 2
# kk {"k3"=>"v3"} {:kk=>{"k3"=>"v3"}}

Upvotes: 0

Views: 907

Answers (1)

Renato Zannon
Renato Zannon

Reputation: 29941

Ruby interpreted the second example as an array with a single hash as its element (the curly braces are implied). It is equivalent to this:

[{ kk: { 'k1' => 'v1' }, kk: { 'k2' => 'v2' }, kk: { 'k3' => 'v3' }}]

Only the last 'kk' is shown because hashes can't have duplicate keys; only the last one sticks.

If you want an array with multiple hashes as elements, you need to use the syntax like on your first example.


More examples on which ruby implies a hash start:

# Only argument on method calls
def only_arg(obj)
  puts obj.class
end

only_arg(bar: "baz")  # => Hash

# Which is equivalent to:
only_arg({bar: "baz"}) # => Hash


# Last argument on method calls
def last_arg(ignored, obj)
  puts obj.class
end

last_arg("ignored", bar: "baz") # => Hash

# Which is equivalent to:
last_arg("ignored", { bar: "baz" }) # => Hash


# Last element on an array
def last_on_array(arr)
  puts arr.last.class
end

last_on_array(["something", "something", bar: "baz"]) # => Hash

# Which is equivalent to:
last_on_array(["something", "something", { bar: "baz" }]) # => Hash

Upvotes: 5

Related Questions