Get non-missing type in the case of parametric type

So I was looking at how to get T from a Union{Missing,T} and came up with

nonmissing(TT::Type{Union{Missing,T}}) where T = T
nonmissing(TT::Type{T}) where T = T

(PS: incidentally I found that @bkamins had answered something similar on stackoverflow https://stackoverflow.com/questions/52118361/is-there-a-type-subtraction-operation-in-julia so it looks like this is not a bad idea)

This works fine for non-parametric types including abstract types:

julia> nonmissing(Union{Missing,Real}) == Real

However when there’s a parametric type, it returns the union

julia> struct Foo{N} end
julia> nonmissing(Union{Missing,Foo}) == Union{Missing,Foo}

Is there a way to recuperate Foo in this case? One way I found around it that works is to write a macro but I feel that’s overkill here…

macro nonmissing(ex)
  ex isa Symbol && return ex
  types = ex.args[2:end]
  types[1] == :Missing && return types[2]
  return types[1]
end

thanks

Hmm I guess this does the job:

nomiss(::Type{T}) where T = T isa Union ? ifelse(T.a == Missing, T.b, T.a) : T

but I’ll take anything that’s more elegant than that or the macro :slightly_smiling_face:

1 Like

Well now (SO answer is old :slight_smile: and things move forward) you have nonmissingtype defined as:

nonmissingtype(::Type{S}) where {S} = Core.Compiler.typesubtract(S, Missing)

and it does the job as expected (please correct me if I missed something).

2 Likes

Nice, thanks, unfortunately that won’t work on older versions of Julia right? it doesn’t on 1.0. as far as I can tell. (for Union{Missing,Foo} it will return Union{Missing,Foo})

I guess I could do a version check and either use that or the nomiss thing.

Thanks either way!

You can use Missings.jl, which exports nonmissingtype on older Julia versions.

1 Like