How to create a union type out of an array literal?

I can easily convert a union type into an ArrayLiteral. Is there also a way to do it the other way around?

I’d like to reduce a union type and make a new one out of it…

alias X = Int32|String|Nil
{% if true %}
{{ X.union_types.select {|el| el != Nil} }}
{{debug}}
{% end %}

I don’t think union types can be “dynamically” created, in the sense that the types are known but reducing the types to another type via the macro methods would count them as dynamically created.

You can actually do this by using the Union type directly. E.g.

alias X = Int32|String|Nil

{% if true %}
  {% types = X.union_types.select {|el| el != Nil} %}
  alias Y = {{"Union(#{types.join(",").id})".id}}
  
  {{debug}} # => alias Y = Union(Int32, String)
{% end %}
  
y : Y = 1

pp y # => 1
2 Likes

I just realized it doesn’t help me (yet) completely…
The solution works for alias types (X in example), but not for generic types (T in example); is there a solution for this as well?

alias X = Int32|String|Nil

class C(T)
    {{"alias U = Union(#{X.union_types.select {|el| el != Nil}.join(",").id})".id}} # X works, but T doesn't
    def initialize
        p U
    end
end

C(X).new

That said, having a subtract operation in type algebra would be nice.

1 Like

It seems macros are rather restrictive:

alias X = Int32|String|Nil

class C(T)
    {{"alias U = Union(#{X.union_types.select {|el| el != Nil}.join(",").id})".id}} # X works, but T doesn't
    # @x : {{"Union(#{T.union_types.select {|el| el != Nil}.join(",").id})".id}} = 0 # doesn't work for neither X nor T
    def initialize
        p {{"Union(#{T.union_types.select {|el| el != Nil}.join(",").id})".id}} # both X and T work
        # @x = 0.as({{"Union(#{T.union_types.select {|el| el != Nil}.join(",").id})".id}}) # doesn't work for neither X nor T
        # @x = 0.as(Int32|String) # works
    end
end

C(X).new

In particular:

  • the locations where macro substitutions {{...}} can be put are restricted (e.g. not where types are expected, after double colon or with #as
  • generic type usage is working only inside methods

Which makes me wonder since I now learned we can put almost all code in macros this way: {{"p 42; p 12".id}}