I'm doing a code challenge in Crystal. As someone who with a Ruby background who went on to learn Rust, you might think that it's a natural fit. However, I'm finding it to fall in the uncanny valley between the two - not as flexible as Ruby and not as expressive a type system as Rust, and the two play off of each other when I'm trying to do type gymnastics to get this very Ruby-like language to behave like Ruby.
I want a RecursiveHash with values of the type RecursiveHash. Basically this in Ruby:
h = {}
h[:a] = {}
So if you start writing it in Crystal, you get:
hash = Hash(Char, Hash(Char, ???)).new
And I won't know how many levels deep the Hash is until runtime.
@briankung DefaultDict of DefaultDict!
@EndlessMason IIUC that's basically what I want! Is that a Python thing?
@briankung Yes. It's a python thing...
In perl we call it a hash-ref, they just do be like that
@briankung it's not as ergonomic as ruby, but in crystal you can declare recursive type aliases, which help with that specific problem:
alias RecursiveHash::Types = Hash(Char, RecursiveHash::Types) | String h = Hash(Char, RecursiveHash::Types).new h['a'] = Hash(Char, RecursiveHash::Types).new h['b'] = "B" a = h['a'].as(Hash(Char, RecursiveHash::Types)) a['a'] = Hash(Char, RecursiveHash::Types).new a['b'] = "BB"
the cost is some syntax to cast the union type to the specific recursive type, but you avoid static nested types.
@toddsundsted Ah, gotcha, I see where I went wrong. I was trying something similar but tried to use h = RecursiveHash(...). Thank you so much!
@briankung no problem! the JSON::Any
implementation (link) in the crystal standard library is an excellent example to follow.