# Unpack types in Union

**URL:** https://discourse.julialang.org/t/unpack-types-in-union/75803
**Category:** General Usage
**Tags:** question
**Created:** [February 4, 2022, 3:27pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803 "2022-02-04T15:27:45Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![gcalderone](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gcalderone/32/1539_2.png) [@gcalderone](https://discourse.julialang.org/u/gcalderone)
#### Post date: [February 4, 2022, 3:27pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/1 "2022-02-04T15:27:45Z")

</div>

I would like to extract a `Vector{DataType}` from a `Union`. I found the solution shown below, but it looks weird to me, and non-idiomatic.  
Is there a better way to unpack types in a `Union`?

My solution:

```julia
unpack_union(tt::Core.TypeofBottom) = DataType[]
unpack_union(tt::DataType) = [tt]
unpack_union(tt::Union) = 
    [getfield(tt, :a), unpack_union(getfield(tt, :b))...]

```

providing the following results:

```julia
julia> unpack_union(Union{})
DataType[]

julia> unpack_union(Union{Int})
1-element Vector{DataType}:
 Int64

julia> unpack_union(Union{Int, String})
2-element Vector{DataType}:
 Int64
 String

julia> unpack_union(Union{Int, String, Missing})
3-element Vector{DataType}:
 Missing
 Int64
 String

```

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [February 4, 2022, 3:29pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/2 "2022-02-04T15:29:09Z")

</div>

and why is that you want to do this? making sure it’s not an XY problem…

---

<div class="post-metadata">

### Author: ![gcalderone](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gcalderone/32/1539_2.png) [@gcalderone](https://discourse.julialang.org/u/gcalderone)
#### Post date: [February 4, 2022, 3:30pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/3 "2022-02-04T15:30:56Z")

</div>

Sorry, don’t know what is a XY problem…  
Still, I think the question worth an answer (even if my problem could be solved differently…).

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [February 4, 2022, 3:32pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/4 "2022-02-04T15:32:39Z")

</div>

> **[The XY Problem](https://xyproblem.info/)**
>
> Asking about your attempted solution rather than your actual problem

> [@gcalderone](#):
>
> I think the question worth an answer

there are a lot of code smell you can do, doesn’t mean you should

---

<div class="post-metadata">

### Author: ![gcalderone](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gcalderone/32/1539_2.png) [@gcalderone](https://discourse.julialang.org/u/gcalderone)
#### Post date: [February 4, 2022, 3:34pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/5 "2022-02-04T15:34:34Z")

</div>

Thank you, I didn’t knew it!

> [@jling](#):
>
> there are a lot of code smell you can do, doesn’t mean you should

Indeed, I don’t want to. That’s why I asked what is the correct way to do it…

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [February 4, 2022, 3:35pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/6 "2022-02-04T15:35:16Z")

</div>

that’s why I asked what do you need this for?

---

<div class="post-metadata">

### Author: ![gcalderone](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gcalderone/32/1539_2.png) [@gcalderone](https://discourse.julialang.org/u/gcalderone)
#### Post date: [February 4, 2022, 3:39pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/7 "2022-02-04T15:39:14Z")

</div>

I would like to keep the discussion focus on the topic, so forget about my proposed solution (which I really don’t like…) and think of it as simply:

Is there an idiomatic way to unpack types in a `Union` ?

Even “no” is an acceptable answer 😉

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [February 4, 2022, 3:40pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/8 "2022-02-04T15:40:54Z")

</div>

the answer is you shouldn’t be doing that, so if it turns out you really need to, please show us the use case so people can help you.

---

<div class="post-metadata">

### Author: ![gcalderone](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gcalderone/32/1539_2.png) [@gcalderone](https://discourse.julialang.org/u/gcalderone)
#### Post date: [February 4, 2022, 3:46pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/9 "2022-02-04T15:46:11Z")

</div>

> [@jling](#):
>
> the answer is you shouldn’t be doing that

OK, I can live with it. It’s not clear to me why such introspection should be discouraged or forbidden, given all the amazing Julia features (think about macros…)  
But this is definitely **not the point I’m interested in**.

Thank you for your answer.

---

<div class="post-metadata">

### Author: ![trahflow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/trahflow/32/30585_2.png) [@trahflow](https://discourse.julialang.org/u/trahflow)
#### Post date: [February 4, 2022, 3:47pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/10 "2022-02-04T15:47:44Z")

</div>

> [@gcalderone](#):
>
> but it looks weird to me, and non-idiomatic.

doesn’t look that horrible to me 🙂  
I would maybe hide everything behind another function:

```julia
function unpack_union(tt::Union)
    _unpack_union(tt::Core.TypeofBottom) = DataType[]
    _unpack_union(tt::DataType) = [tt]
    _unpack_union(tt::Union) = [getfield(tt, :a), _unpack_union(getfield(tt, :b))...]
    _unpack_union(tt)
end

```

---

<div class="post-metadata">

### Author: ![gcalderone](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gcalderone/32/1539_2.png) [@gcalderone](https://discourse.julialang.org/u/gcalderone)
#### Post date: [February 4, 2022, 3:56pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/11 "2022-02-04T15:56:35Z")

</div>

> [@trahflow](#):
>
> doesn’t look that horrible to me

Well, consider the following:

- a `Union` is definitely not a structure, still you can use it in `getfield`;
- `propertynames()` always returns two names (`a` and `b`), the second being a nested `Union` if more than two types ar involved;
- the property names `a` and `b` to access the types in a `Union` are not documented in the manual (AFAIK).

Anyway good to know that it doesn’t sound horrible!

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [February 4, 2022, 4:33pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/12 "2022-02-04T16:33:26Z")

</div>

I mean, you’re definitely depending upon internals — Unions can behave surprisingly and sometimes disappear entirely, depending on how they’re being generated. Defining dispatch on `::Union` can be tricky (as you’ve found with `TypeofBottom` and such). You’re definitely well outside of what inference can possibly track, but that’s not necessarily a bad thing.

I’d try to reformulate your problem such that you don’t need to do this, if at all possible.

---

<div class="post-metadata">

### Author: ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)
#### Post date: [September 14, 2025, 9:06am UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/13 "2025-09-14T09:06:14Z")

</div>

Sometimes a data-reading library returns arrays of `Union{Missing, Float64}` or `Union{Missing, Float32}`. Because some other libraries (packages) I use doesn’t handle `missing`, I sometimes need to convert the `missing` values to `NaN`s.

So, how do you determine the second element of the `Union`?

```julia
function readalldata()
  a = readdata()
  b = replace(a, missing=>eltype_of_data(NaN)) # how to determine the type?
  return b
end

```

Because in my case there are only two possibilities, I can branch like

```julia
eltorg = eltype(a)
elt = if eltorg == Union{Missing,Float64}
        Float64
      elseif eltorg == Union{Missing,Float32}
        Float32
      else
        error("unknown type: $(eltorg)")
      end
b = replace(a, missing => elt(NaN))

```

Inellegant, but manageable.

Also, I know that the right approach is to ask the package writers to support `missing` . . .

---

<div class="post-metadata">

### Author: ![jakobjpeters](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobjpeters/32/207797_2.png) [@jakobjpeters](https://discourse.julialang.org/u/jakobjpeters)
#### Post date: [September 14, 2025, 12:33pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/14 "2025-09-14T12:33:26Z")

</div>

How about [`nonmissingtype`](https://docs.julialang.org/en/v1/base/base/#Base.nonmissingtype)?

Friendly suggestion that it would probably better to create a new thread, and perhaps linking to this one, instead of posting in one that’s been inactive for over 3 years 🙂

---

<div class="post-metadata">

### Author: ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)
#### Post date: [September 15, 2025, 1:48pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/15 "2025-09-15T13:48:03Z")

</div>

> [@jakobjpeters](#):
>
> How about [`nonmissingtype`](https://docs.julialang.org/en/v1/base/base/#Base.nonmissingtype)?

Thanks! But, it’s curious how the function is implemented. See below.

> [@](#):
>
> Friendly suggestion that it would probably better to create a new thread, and perhaps linking to this one, instead of posting in one that’s been inactive for over 3 years 🙂

That depends on the subject of the new thread you are suggesting. If you suggest starting a thread about getting the other part of `Union{Missing, Sometype}`, then `nonmissingtype` is the solution, but this thread is more general: How to deconstruct a `Union`, which hasn’t gotten a clean and idiomatic answer.

I just continued this thread to provide an example where such a functionality is useful, because the original poster was blamed of not providing a use case.

So, to continue, `nonmissingtype` is implemented like this

```julia
nonmissingtype(::Type{T}) where {T} = typesplit(T, Missing)

```

But, I’m not able to find how `typesplit()` is defined. (I don’t know github well enough.) I tested it a bit and found that it works on any `Union`. It acts like subtracting a type from the Union:

```julia
Base.typesplit(Union{S,T,U}, T) == Union{S,U}

```

Inside the function there must be an iteration to go over `S`, `T`, and `U` one by one. Does this iteration uses the `:a` and `:b` trick discussed above?

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [September 15, 2025, 4:03pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/16 "2025-09-15T16:03:07Z")

</div>

> [@ryofurue](#):
>
> how `typesplit()` is defined

```julia-repl
julia> methods(Base.typesplit)
# 1 method for generic function "typesplit" from Base:
 [1] typesplit(a, b)
     @ promotion.jl:147

```

> <https://github.com/JuliaLang/julia/blob/2e26583cd9f55c7862c2c3ce03691f1ecd0a603a/base/promotion.jl#L143-L158>

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [September 15, 2025, 4:04pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/17 "2025-09-15T16:04:48Z")

</div>

> [@ryofurue](#):
>
> this thread is more general: How to deconstruct a `Union`, which hasn’t gotten a clean and idiomatic answer.

> <https://github.com/JuliaLang/julia/issues/53193>
>
> Useful functionality like \`Base.typesplit\` or \`Base.promote\_union\` may be implem…ented by recursively mapping over the components of a \`Union\` object. I wonder if it would make sense to provide a public API so users could do that themselves. I guess either of these would be nice:
> 
> 1. document and support the \`a\` and \`b\` fields of a \`Union\`, or
> 
> 2. provide some higher level API similar to \`mapreduce\`, that would take a type instead of a collection, interpreting union components as collection elements

---

<div class="post-metadata">

### Author: ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)
#### Post date: [September 17, 2025, 5:10pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/18 "2025-09-17T17:10:25Z")

</div>

@nsajko Very nice! Thank you. So, `typesplit()` does use the `:a` and `:b` internals and [public API accessing Union components](https://github.com/JuliaLang/julia/issues/53193) is being considered.

That’s a proper continuation of this thread.

---

<div class="post-metadata">

### Author: ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)
#### Post date: [September 17, 2025, 7:14pm UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/19 "2025-09-17T19:14:43Z")

</div>

We really do need a way to look at each member of union type that is stable. A good amount of packages end up touching stuff related to `UnionAll` and `Union` that is internal API.

I think one of the big issues in the way of progress here is the conflict between what a `Union` is conceptually and the reality of its implementation. Although the implementation of `Union` is in of itself a collection, it is conceptually a type whose subtypes my be non-finite. This doesn’t mean we can’t do anything with types that subtype an unknown quantity of other types. After all we have methods like `typejoin` and `typeintersect` that work on `Union`. However, defining something that is conceptually robust and functionally useful can get pretty difficult.

For example, let’s say you want `typediff(lhs, rhs) -> ty` so that `!(ty <: rhs) && (ty <: lhs)`. The practical application may at first seem simple and useful (`typediff(Union{Int, Char, Symbol}, Int) -> Union{Char, Symbol}`), but what do you do for `typediff(Union{Integer Char, Symbol}, Int)`? You have to decide whether you want to create a new union including every subtype except `Int` or if there’s a meaningful heuristic where we can agree that `typediff` gives up.

Unless the goal is literally to convert between types, we usually care more about some trait related `lhs` than the type itself. In which case, you really do just want to check some trait on each member in a union. This might be okay if poking around inside of `Union` was alright to do, but I don’t think everyone has agreed that the current implementation is what we want forever.

---

<div class="post-metadata">

### Author: ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)
#### Post date: [September 18, 2025, 5:03am UTC](https://discourse.julialang.org/t/unpack-types-in-union/75803/20 "2025-09-18T05:03:29Z")

</div>

```julia-auto
typediff(Union{Int, Char, Symbol}, Int) # -> Union{Char, Symbol}
typediff(Union{Integer Char, Symbol}, Int) # -> ???

```

I see!

Initially, I naïvely thought, why not use the `AbstractSet` API for `Union` ? But, now I realize that types has not only equality but also subtyping `<:` . So, it’s like a set of sets and `<:` is like `⊆`.

So, it all depends how you would use, or what you want from, `typediff()`. I’m far from knowledgeable enough about the implementation of the Julia languge to go further than this point in a meaningful way. . . . my useless thought is, if we use the “set of sets” analogy, “diff” is “xor” and

```julia-auto
{Integer, Char, Symbol} xor {Int} == {Integer, Char, Symbol, Int}

```

because here we use only equality to define “diff”, but I guess that’s not what you want in the implementation of the language.

[Next page](https://discourse.julialang.org/t/unpack-types-in-union/75803.md?page=2)
