# Hash litterals with recursive alias issue

**URL:** <https://forum.crystal-lang.org/t/hash-litterals-with-recursive-alias-issue/3502>\
**Category:** Help & Support\
**Created:** [July 12, 2021, 5:25pm UTC](https://forum.crystal-lang.org/t/hash-litterals-with-recursive-alias-issue/3502 "2021-07-12T17:25:52Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![hutou](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/hutou/32/1337_2.png) [@hutou](https://forum.crystal-lang.org/u/hutou)\
**Post date:** [July 12, 2021, 5:25pm UTC](https://forum.crystal-lang.org/t/hash-litterals-with-recursive-alias-issue/3502/1 "2021-07-12T17:25:52Z")

</div>

Working with hash tables in Crystal is not always ‘crystal’ clear to me ☹  
So, given the following type:  
`alias Params = String | Int32 | Hash(Symbol, Params)`

I want to define and populate a hash table with, for example, the following literal data:

```auto
foo = {
:bar1 => {:type => "I", :minval => 3, :maxval => 33}, 
:bar2 => {:type => "I", :minval => 4, :maxval => 44}, 
:bar3 => {}
}

```

Applying the advice given by @Blacksmoke16 in a [previous post](https://forum.crystal-lang.org/t/modify-contents-of-parsed-yaml/3050/2), I end up with the following code:

```auto
foo = {} of Symbol => Params
 
foo[:bar1] = {} of Symbol => Params
foo[:bar2] = {} of Symbol => Params
foo[:bar3] = {} of Symbol => Params
 
foo[:bar1].as(Hash(Symbol, Params))[:type] = "I"
foo[:bar1].as(Hash(Symbol, Params))[:minval] = 3
foo[:bar1].as(Hash(Symbol, Params))[:maxval] = 33
foo[:bar2].as(Hash(Symbol, Params))[:type] = "I"
foo[:bar2].as(Hash(Symbol, Params))[:minval] = 4
foo[:bar2].as(Hash(Symbol, Params))[:maxval] = 44

p! foo
p! typeof(foo)
p! typeof(foo[:bar1])
p! typeof(foo[:bar1].as(Hash(Symbol, Params))[:maxval])

```

and the result is what I expect.

```auto
foo # => {:bar1 => {:type => "I", :minval => 3, :maxval => 33}, :bar2 => {:type => "I", :minval => 4, :maxval => 44}, :bar3 => {}
typeof(foo) # => Hash(Symbol, Params)
typeof(foo[:bar1]) # => (Hash(Symbol, Params) | Int32 | String)
typeof((foo[:bar1].as(Hash(Symbol, Params)))[:maxval]) # => (Hash(Symbol, Params) | Int32 | String)

```

But the syntax is a bit heavy, I think. So I try a more compact version:

```auto
foo = {
  :bar1 => {:type => "I".as(Params), :minval => 3.as(Params)}.as(Params),
  # :bar2 => {:type => "I".as(Params), :minval => 4.as(Params), :maxval => 44.as(Params)}.as(Params),
}
p! foo
p! typeof(foo)
p! typeof(foo[:bar1])

```

This looks ok:

```auto
foo # => {:bar1 => {:type => "I", :minval => 3}}
typeof(foo) # => Hash(Symbol, Params)
typeof(foo[:bar1]) # => (Hash(Symbol, Params) | Int32 | String)

```

but, if I uncomment the second line (:bar2 …), I get the following compilation error:  
`Error: can't cast Hash(Symbol, Hash(Symbol, Params) | Int32 | String) to Params`

Why is adding a 3rd key a problem? I read somewhere that recursive aliases are a bit buggy: is this the explanation of this error?

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [July 12, 2021, 5:34pm UTC](https://forum.crystal-lang.org/t/hash-litterals-with-recursive-alias-issue/3502/2 "2021-07-12T17:34:39Z")

</div>

I would highly suggest not using recursive hashes like this and think of a different approach. Possibly something like how [JSON::Any - Crystal 1.1.0-dev](https://crystal-lang.org/api/master/JSON/Any.html) is implemented. I.e. a struct which stores an ivar that has a type of a big union of various primitive types, and other `JSON::Any` instances: [JSON::Any::Type - Crystal 1.1.0-dev](https://crystal-lang.org/api/master/JSON/Any/Type.html).

Or really, just do something like:

```auto
record Param, type : String, minval : Int32, maxval :Int32

foo = {
  "bar1" => Param.new("I", 3, 33),
  "bar2" => Param.new("I", 4, 44),
}

```

I’d also not advise using symbols like this as in Crystal land they don’t really have any benefit over String.

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [July 12, 2021, 6:03pm UTC](https://forum.crystal-lang.org/t/hash-litterals-with-recursive-alias-issue/3502/3 "2021-07-12T18:03:36Z")

</div>

It looks like a bug. But you can use `{ ... } of Symbol => Params` instead of doing `{ ... }.as(Params)`. But you should probably avoid using recursive aliases at all.
