This is related to How to create a union type out of an array literal?
My original issue started out with a generic table that was supposed to get a (parametrized) reference type in addition. When I added the type, the compiler started complaining (two
below), rightly so.
Since I was not able to deduce the underlying base type BaseCell
inside Table(T)
with the help of macros, I started passing both types to the generic class; which works, but somehow feels unwieldy.
In my non-reduced code I need even more generic types, so it gets kind of confusing.
I wonder if I miss some more elegant way…
# e.g. `crystal run -Done reference.cr`
{% if flag?(:one) %}
# this works
class Table(T)
@value : T|Nil = nil
def m
@value = ReferenceCell.new
end
end
class ReferenceCell
end
alias BaseCell = Int32|Nil
alias Cell = BaseCell|ReferenceCell
t = Table(Cell).new
t.m
{% end %}
{% if flag?(:two) %}
# this doesn't work because of the wrong usage of type recursion
class Table(T)
@value : T|Nil = nil
def m
@value = ReferenceCell(T).new # T is wrong here, would need BaseCell instead
# Error: instance variable '@value' of Table(Int32 | ReferenceCell(Int32 | Nil) | Nil)
# must be (Int32 | ReferenceCell(Int32 | Nil) | Nil)
# not ReferenceCell(Int32 | ReferenceCell(Int32 | Nil) | Nil)
end
end
class ReferenceCell(T)
end
alias BaseCell = Int32|Nil
alias Cell = BaseCell|ReferenceCell(BaseCell)
t = Table(Cell).new
t.m
{% end %}
{% if flag?(:three) %}
# works again
class Table(T,U) # outward type, inner reference type
@value : T|Nil = nil
def m
@value = ReferenceCell(U).new
end
end
class ReferenceCell(T)
end
alias BaseCell = Int32|Nil
alias Cell = BaseCell|ReferenceCell(BaseCell)
t = Table(Cell, BaseCell).new
t.m
{% end %}