Julia: Custom Missing-like structs don't infer with map (but Missing does)

Created on 30 Oct 2020  路  6Comments  路  Source: JuliaLang/julia

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?

missing data

All 6 comments

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?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wilburtownsend picture wilburtownsend  路  3Comments

yurivish picture yurivish  路  3Comments

m-j-w picture m-j-w  路  3Comments

iamed2 picture iamed2  路  3Comments

dpsanders picture dpsanders  路  3Comments