https://play.crystal-lang.org/#/r/8dmj
class Zone
property update_buffer = Array(Hash(Int64, Array(Array(Int32 | String)))).new
end
zone1 = Zone.new
#zone1.update_buffer += [[0, [0]]]
#pp zone1.update_buffer
total_game_buffer = Array(Hash(Int64, Array(Array(Int32 | String)))).new
total_game_buffer += [[0, [0]]]
pp total_game_buffer
I just extracted this out of my game loop because I was like wtf is going on :D
Questions:
- Why does
total_game_buffer
work, when [[0, [0]]]
does not match an Array of Hashes?
- How come the type declaration of Array(Hash(Int64, Array(Array(Int32 | String)))).new gives an error if it’s inside a class and assigned to an
ivar
, but not with a local variable?
a += b
expands to a = a + b
. The type of a
after this expression is determined by the result of the right hand side expression: typeof(a) = typeof(a + b)
. The method Array#+
concatenates two arrays and returns the result. The generic type argument of the returned array is the union of the two operands’ generic type arguments: Array(T)#+(Array(U))
returns Array(A | U)
.
That should explain the first question.
The second answer: Local variables behave the same as ivars if you declare a type restriction. Usually you wouldn’t do that (like in the example) and thus the compiler can change the type of the local variable according to the result type assigned to it.
You can insert a few p typeof(total_game_buffer)
to see that.
1 Like
Thanks for the explanation.
and thus the compiler can change the type of the local variable according to the result type assigned to it.
Aww. Interesting
I’m going to refactor some stuff with this new info ;)