The following code fails to compile with error:
type must be Tuple(Thing::Ish, Slice(UInt8)), not Tuple(Array(Array(Thing::Ish) | UInt8) | UInt8, Slice(UInt8))
These two types seem equivalent to me... and adding an .as(Ish)
in the right place works... what am I missing? Why do these types not unify?
module Thing
alias Ish = UInt8 | Array(Ish)
def self.decode(bytes : Bytes) : {Ish, Bytes}
case bytes[0]
when 0x00..0x17
{bytes[0], bytes + 1}
when 0x18
MultiItemDecoder.new(0x80, ->(x: Bytes) { Thing.decode(x) }).decode(bytes)
else
raise "unknown"
end
end
class MultiItemDecoder(T)
def initialize(@base : UInt8, @item_decoder : Bytes -> {T, Bytes})
end
def decode(bytes): {Array(T), Bytes}
decode_some(bytes + 1, bytes[0])
end
def decode_some(bytes, n)
items = n.times.map do
item, bytes = @item_decoder.call(bytes)
item
end
{items.to_a, bytes}
end
end
end
This works:
module Thing
alias Ish = UInt8 | Array(Ish)
def self.decode(bytes : Bytes) : {Ish, Bytes}
case bytes[0]
when 0x00..0x17
{bytes[0], bytes + 1}
when 0x18
MultiItemDecoder.new(0x80, ->(x : Bytes) { Thing.decode(x) }).decode(bytes)
else
raise "unknown"
end
end
class MultiItemDecoder(T)
def initialize(@base : UInt8, @item_decoder : Bytes -> {T, Bytes})
end
def decode(bytes) : {Ish, Bytes}
decode_some(bytes + 1, bytes[0])
end
def decode_some(bytes, n)
items = n.times.map do
item, bytes = @item_decoder.call(bytes)
item.as(Ish)
end
{items.to_a.as(Ish), bytes}
end
end
end
Thing.decode(Bytes[1, 2, 3])
The thing is that Array(Array(Ish))
is not an Array(Ish)
, because for that it must be Array(Array(Ish) | UInt8)
(note that it's an array of a union).
This all boils down to how things are represented in memory.
My advice is to avoid using recursive aliases. They are not intuitive and we might eventually remove them from the language.