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?
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 ?
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.
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.
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 NaNs.
So, how do you determine the second element of the Union?
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
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 . . .
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
Thanks! But, it’s curious how the function is implemented. See below.
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
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:
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?