# Iterating through the types of a union type

**URL:** <https://forum.crystal-lang.org/t/iterating-through-the-types-of-a-union-type/2179>\
**Category:** Help & Support\
**Created:** [May 27, 2020, 6:02am UTC](https://forum.crystal-lang.org/t/iterating-through-the-types-of-a-union-type/2179 "2020-05-27T06:02:58Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![BrucePerens](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/bruceperens/32/852_2.png) [@BrucePerens](https://forum.crystal-lang.org/u/BrucePerens)\
**Post date:** [May 27, 2020, 6:02am UTC](https://forum.crystal-lang.org/t/iterating-through-the-types-of-a-union-type/2179/1 "2020-05-27T06:02:58Z")

</div>

I have this union type defined:

```
module Hierarchical
  extend self
  alias Types = Folder | Forum | Language | Manufacturer | Product | Topic | Page | Post
end

```

I would like to iterate through the types in a macro, so that I iterate upon Folder, Forum, …  
I couldn’t quite figure out how to write that from the docs. It would be something like

```
{% for type in Hierarchical::Types.union_types %}
  do_something_with( type.name )
{% end %}

```

but that’s not working. On the first iteration I get the name of the common superclass of all of my union types, with a “+” at the end.

```
Thanks

Bruce
```

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [May 27, 2020, 10:25am UTC](https://forum.crystal-lang.org/t/iterating-through-the-types-of-a-union-type/2179/2 "2020-05-27T10:25:28Z")

</div>

The compiler merges unions of types that inherit from `Superclass` as `Superclass+`. This is typically useful to reduce the amount of overall types the compiler needs to keep track of when those unions just come together by chance (for example `Folder.new || Forum.new`).

This is of course unexpected behaviour when there’s an explicit definition link in your case and you expect to get the actual values you specified. There’s an open issue about that (or rather a related case, `alias` isn’t mentioned explicitly) at [https://github.com/crystal-lang/crystal/issues/9050](https://github.com/crystal-lang/crystal/issues/9050) and a PR at [https://github.com/crystal-lang/crystal/pull/9052](https://github.com/crystal-lang/crystal/pull/9052)

---

<div class="post-metadata">

**Author:** ![jgaskins](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jgaskins/32/2449_2.png) [@jgaskins](https://forum.crystal-lang.org/u/jgaskins)\
**Post date:** [May 27, 2020, 10:31am UTC](https://forum.crystal-lang.org/t/iterating-through-the-types-of-a-union-type/2179/3 "2020-05-27T10:31:30Z")

</div>

This should get you on the right track:

```crystal
abstract struct Foo
end

{% for type in %w[Folder Forum Language Manufacturer Product Topic Page Post] %}
  struct {{type.id}} < Foo
  end
{% end %}

module Hierarchical
  extend self
  alias Types = Folder | Forum | Language | Manufacturer | Product | Topic | Page | Post
end

{% for type in Hierarchical::Types.union_types %}
  {% if type.subclasses.any? { |s| s } %}
   {% for subtype in type.subclasses %}
     {% pp subtype %}
   {% end %}
  {% else %}
    {% pp type %}
  {% end %}
{% end %}

```

It works with and without the inheritance, you’ll just need to make sure you do the same thing with `subtype` as with `type` if you want to support both, maybe by extracting the behavior to a macro.

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [May 27, 2020, 2:33pm UTC](https://forum.crystal-lang.org/t/iterating-through-the-types-of-a-union-type/2179/4 "2020-05-27T14:33:25Z")

</div>

This is an entirely different angle. Your example prints _all_ subclasses of `Foo`, even those not included in `Hierarchical::Types`.  
If you add `struct Bar < Foo; end` to the code, it get’s listed as members of `Hierarchical::Type`. This techincally correctly reflects how the compiler treats this union, but it probably doesn’t fit the intended use case of that union. If it did, there would be no reason to list the sublasses explicitly as union members, you could just use the superclass (either directly or as a union with non-inherited types).

---

<div class="post-metadata">

**Author:** ![jgaskins](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jgaskins/32/2449_2.png) [@jgaskins](https://forum.crystal-lang.org/u/jgaskins)\
**Post date:** [May 27, 2020, 4:44pm UTC](https://forum.crystal-lang.org/t/iterating-through-the-types-of-a-union-type/2179/5 "2020-05-27T16:44:48Z")

</div>

Ah, good point

---

<div class="post-metadata">

**Author:** ![j8r](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/j8r/32/111_2.png) [@j8r](https://forum.crystal-lang.org/u/j8r)\
**Post date:** [May 28, 2020, 5:12pm UTC](https://forum.crystal-lang.org/t/iterating-through-the-types-of-a-union-type/2179/6 "2020-05-28T17:12:54Z")

</div>

A tuple that holds all the type classes can be used:

```crystal
class A
end

class B < A
end

module Hierarchical
  extend self
  {% begin %}
  {% types = %w(A B)%}
  alias Types = {{types.join(" | ").id}}
  TypesTuple = { {{types.join(", ")}} }
  {% end %}
end

{% for type in Hierarchical::TypesTuple %}
  puts {{type}}
{% end%}

```
