4

Given the following code:

require "big"

alias Type = Nil | String | Bool | Int32 | BigFloat | Array(Type) | Hash(String | Symbol, Type)
alias HOpts = Hash(String | Symbol, Type)

ctx = HOpts.new
ctx["test_int"] = 1
ctx["test_s"] = "hello"

c1 = Hash(String, Type).new
ctx["stuff"] = c1
ctx["stuff"]["foo"] = { "bar" => 1 }

I get:

Error in test.cr:13: instantiating 'Hash(String | Symbol, Type)#[]=(String, Hash(String, Type))'

ctx["stuff"] = c1
   ^

in /opt/crystal/src/hash.cr:43: instantiating 'insert_in_bucket(Int32, String, Hash(String, Type))'

    entry = insert_in_bucket index, key, value
            ^~~~~~~~~~~~~~~~

in /opt/crystal/src/hash.cr:842: instantiating 'Hash::Entry(String | Symbol, Type)#value=(Hash(String, Type))'

          entry.value = value
                ^~~~~

in /opt/crystal/src/hash.cr:881: expanding macro

    property value : V
    ^

in macro 'property' expanded macro: macro_83313872:567, line 10:

   1.       
   2.         
   3.           
   4.             @value : V
   5. 
   6.             def value : V
   7.               @value
   8.             end
   9. 
> 10.             def value=(@value : V)
  11.             end
  12.           
  13.         
  14.       
  15.     

instance variable '@value' of Hash::Entry(String | Symbol, Type) must be Type, not Hash(String, Type)

I would expect to be able to create any kind of nested hash but it does not work.

Vitalii Elenhaupt
  • 7,146
  • 3
  • 27
  • 43
binduck
  • 41
  • 1

1 Answers1

3

There's a couple of things wrong here.

The type of c1 is Hash(String, Type) which is not one of the types of the Type union. Hash(String, Type) is not compatible with Hash(String | Symbol, Type).

Either include Hash(String, Type) in the Type union, or give c1 the type Hash(String | Symbol, Type) (i.e. HOpts):

c1 = HOpts.new

You will also have another error on this line of code:

ctx["stuff"]["foo"] = { "bar" => 1 }

ctx["stuff"] will return an object of type Type and not a hash as you expect. If you know for certain that ctx["stuff"] is a hash (which we do from this example) then you need to restrict its type. Also { "bar" => 1 } is of type Hash(String, Int32) and not Hash(String, Type), so you need to specify this too:

ctx["stuff"].as(HOpts)["foo"] = HOpts{ "bar" => 1 }
Decade Moon
  • 32,968
  • 8
  • 81
  • 101