Consider this code:
julia> bar(::Nothing) = missing
bar (generic function with 1 method)
julia> bar(x) = x;
julia> xs = [1, 2, nothing, 4]
4-element Vector{Union{Nothing, Int64}}:
1
2
nothing
4
julia> ys = map(bar, xs)
4-element Vector{Union{Missing, Int64}}:
1
2
missing
4
We can see we get a nice array of small unions in the output.
But if I make my own similar singleton type, then the output is a Array{Any}.
julia> struct Null end
julia> foo(::Nothing) = Null();
julia> foo(x) = x;
julia> xs = [1, 2, nothing, 4]
4-element Vector{Union{Nothing, Int64}}:
1
2
nothing
4
julia> ys = map(foo, xs)
4-element Vector{Any}:
1
2
Null()
4
Is there something extra i need to do, or is the compiler cheating for Missing and Nothing?
Is there something extra i need to do, or is the compiler cheating for Missing and Nothing?
There's a lot of cheating with those two (but not really by the compiler):
https://github.com/JuliaLang/julia/blob/a80f9038c1f51bc3f831b54a0aa6f5b5f5f8e446/base/missing.jl#L41-L70
Here is another example:
julia> struct Foo
x::Ref{Union{Nothing, Float64}}
end
julia> Foo(1)
Foo(Base.RefValue{Union{Nothing, Float64}}(1.0))
julia> struct MyMissing end
julia> struct Bar
x::Ref{Union{MyMissing, Float64}}
end
julia> Bar(1)
ERROR: MethodError: Cannot `convert` an object of type
Int64 to an object of type
Union{MyMissing, Float64}
Closest candidates are:
convert(::Type{T}, ::T) where T at essentials.jl:171
Nice.
Just adding
Base.promote_rule(T::Type{Null}, S::Type) = Union{S, Null}
doesn't seem to make it work.
It would be good to workout exactly what is needed and document it.
https://github.com/KristofferC/LazilyInitializedFields.jl/pull/1/files#diff-0abed87289859febd0e9c73389d5bb7fae46aa675acf8f1a468de7a3b9dcf0a1R95-R124 got me most of the way there. I still think there was something that was not perfect but don't really recall it.
Being extensible wasn't the priority when we implemented this, but maybe it could be made easier and documented. There's also promote_typejoin which isn't part of the public API.
This is based on the explicit promote_typejoin rule, and not inferred by the compiler. It's also not extensible, sorry.
Doesn't this issue remain open to document how to use promote_typejoin for this?
Or to make it extensible?