# How to enable type inference on own types similar to what julia supports for nothing and missing?

**URL:** <https://discourse.julialang.org/t/how-to-enable-type-inference-on-own-types-similar-to-what-julia-supports-for-nothing-and-missing/39418>\
**Category:** General Usage\
**Tags:** question\
**Created:** [May 13, 2020, 6:25pm UTC](https://discourse.julialang.org/t/how-to-enable-type-inference-on-own-types-similar-to-what-julia-supports-for-nothing-and-missing/39418 "2020-05-13T18:25:26Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [May 13, 2020, 6:25pm UTC](https://discourse.julialang.org/t/how-to-enable-type-inference-on-own-types-similar-to-what-julia-supports-for-nothing-and-missing/39418/1 "2020-05-13T18:25:26Z")

</div>

I try to understand when to use Union types versus constructing custom type hierarchies.

One peculiarity is how `nothing` / `missing` behave like you would hope for

```nohighlight
julia> f(x) = isodd(x) ? nothing : Some(x)
julia> f.([1,2,3])
3-element Array{Union{Nothing, Some{Int64}},1}:
 nothing
 Some(2)
 nothing

```

as you can see, this function returns an Array of lovely concrete type. The same works for `missing` by the way.

However if I define my own type, lets say a singleton type like Nothing, type inference is not able to get it, but infers `Any` instead of the lovely `Union` seen above.

```nohighlight
julia> struct MySingleton end
julia> g(x) = isodd(x) ? MySingleton() : Some(x)
julia> g.([1,2,3])
3-element Array{Any,1}:
 MySingleton()
 Some(2)
 MySingleton()

```

I hope that this is not hardcoded somewhere in the typeinference, but that I only need to overwrite some helper functionalities within Base to make the inference work properly. Does someone know which things to overload?

I tried to overload `Base.promote_rule`, however it does not change the above results at all. Hopefully there is some other hidden gem.

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [May 13, 2020, 6:44pm UTC](https://discourse.julialang.org/t/how-to-enable-type-inference-on-own-types-similar-to-what-julia-supports-for-nothing-and-missing/39418/2 "2020-05-13T18:44:17Z")

</div>

Julia does not have any (or at least many) hard-coded features. In this case it’s the promotion machinery at work:

```julia
julia> promote_type(Nothing, Int64)
Union{Nothing, Int64}

```

So you just (?) need to define `promote_type` for your type.

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [May 13, 2020, 6:47pm UTC](https://discourse.julialang.org/t/how-to-enable-type-inference-on-own-types-similar-to-what-julia-supports-for-nothing-and-missing/39418/3 "2020-05-13T18:47:00Z")

</div>

thanks a lot for your reply!  
unfortunately that just does not work.

On top, the julia documentation [Conversion and Promotion · The Julia Language](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/#Defining-Promotion-Rules-1) recommends to overload `promote_rule`, and as said, that does not work either…

* * *

By now I tried to mimic all of `promote_rule` stuff from Nothing

```julia
nonmysingleton(::Type{T}) where {T} = Core.Compiler.typesubtract(T, MySingleton)

Base.promote_rule(T::Type{MySingleton}, S::Type) = Union{S, MySingleton}
# CAUTION: this leads to method ambiguities
function Base.promote_rule(T::Type{>:MySingleton}, S::Type)
    R = nonmysingleton(T)
    Core.println("R = $R")
    R >: T && return Any
    T = R
    R = promote_type(T, S)
    return Union{R, MySingleton}
end

Base.promote_type(T::Type{MySingleton}, S::Type) = Union{S, MySingleton}
Base.convert(::Type{T}, x::T) where {T>:MySingleton} = x
Base.convert(::Type{T}, x) where {T>:MySingleton} = convert(nonmysingleton(T), x)

# EDIT: together with the following two lines it works
Base.promote_typejoin(::Type{MySingleton}, T::Type) = Union{T, MySingleton}
Base.promote_typejoin(T::Type, ::Type{MySingleton}) = Union{T, MySingleton}

```

but still does not work…  
(the `Core.println` actually does not print anything, hence does not get called)

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [May 13, 2020, 7:57pm UTC](https://discourse.julialang.org/t/how-to-enable-type-inference-on-own-types-similar-to-what-julia-supports-for-nothing-and-missing/39418/4 "2020-05-13T19:57:48Z")

</div>

It looks like `Base.promote_typejoin` has some special behavior for `Nothing` and `Missing`. You should be able to implement the same thing for your type by following that example, although I’m not entirely sure that’s the right thing to do.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [May 13, 2020, 7:58pm UTC](https://discourse.julialang.org/t/how-to-enable-type-inference-on-own-types-similar-to-what-julia-supports-for-nothing-and-missing/39418/5 "2020-05-13T19:58:11Z")

</div>

Whoops, forgot to post the relevant link: [julia/promotion.jl at db9063138bbcf8d35ff2e4e55486506602615125 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/blob/db9063138bbcf8d35ff2e4e55486506602615125/base/promotion.jl#L123-L143)

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [May 14, 2020, 4:44am UTC](https://discourse.julialang.org/t/how-to-enable-type-inference-on-own-types-similar-to-what-julia-supports-for-nothing-and-missing/39418/6 "2020-05-14T04:44:25Z")

</div>

Thanks a lot, adding two Base.promote\_typejoin rules solved it,

however now from time to time I get errors, that method resolution is ambiguous now. I think this is be design and denoted by the implementation of missing

> <https://github.com/JuliaLang/julia/blob/db9063138bbcf8d35ff2e4e55486506602615125/base/missing.jl#L47-L70>

as you can see, missing is indeed not only implementing promotion for missing, but also accounts for interactions with nothing. I.e. it seems if you want to add a new type like `MySingleton` you have not only to add the methods above, but you have to model the interactions with all other such types like `nothing` and `missing` from Base.

This together with `Base._promote_type` implementation actually looks like hardcoded to me… you can hack arround but rather complicated and non-intuitive… a bit unfortunate
