Crystal: BUG: Hash merge ambiguous call matches both Int8 and Int16

Created on 23 Aug 2018  路  7Comments  路  Source: crystal-lang/crystal

I get this error while trying update Hash using old value with merge!

My code:

# Error in line 2: instantiating '(Int32 | String)#+(Int32)'
# in line 2: ambiguous call matches both Int8 and Int16

data = {"name" => "user", "age" => 12}
puts data.merge!({"age" => data["age"] + 2})

But this works great:

data = {"name" => "user", "age" => 12}
puts data.merge!({"age" => 13})
puts data.merge!({"age" => 12 + 2})

Playground example:
https://play.crystal-lang.org/#/r/4t4o

Most helpful comment

But that error message ambiguous call matches both Int8 and Int16 looks strange.

All 7 comments

data["age"] can either by a String or an Int32, so that + won't work.

Of course you as the programmer who wrote the code knows that data["age"] is an Int32, but the compiler has no idea, it just sees that you are accessing some element in the Hash.

You can do data["age"].as(Int32) to solve this.

Or probably not use a Hash at all and use classes if you can.

Thanks for explanation

But that error message ambiguous call matches both Int8 and Int16 looks strange.

Hm, right. You can reproduce that with:

a = 1 || "foo"
a + 2

but I'd open that as a separate issue

Works fine with NamedTuple

data = {name: "user", age: 12}
puts data.merge({age: data[:age] + 4})

https://play.crystal-lang.org/#/r/4t7x

@stepanvanzuriak because the types of each key in NamedTuple are known at compile time.

The hash is a mutable object , for example:

data = { :name => "user", :age => 12} #=> Hash(Symbol, Int32 | String)
data[:name] = 12 
data[:age] = "old" 
data # => {:name => 12, :age => "old"}

but the NamedTuple is a inmutable struct, but the type of each key is known by the compiler so it knows
data[:age] is a Int32, so it can respond to :+

data = {name: "user", age: 12} #=> NamedTuple(name: String, age: Int32)

From the docs

The compiler knows what types are in each key, so when indexing a named tuple with a symbol literal the compiler will return the value for that key and with the expected type

Was this page helpful?
0 / 5 - 0 ratings