Null and Array of T question

question
array
type
parametric-types

#1

I am trying to understanding how array operations work and how types work inside arrays. The system is Julia Pro 0.6.0.1 on 64bit Windows 7

The motivating example was

using Nulls
x = [1, null, 2]
typeof(x) # gives Vector{Union{Int64, Nulls.Null}}
y = x + 2
typeof(y) # gives Vector{Any}

So the type of vector changed which isn’t the behaviour I expected. I expected it to have remained at Vector{Union{Int64, Nulls.Null}}

The below is also puzzling. I thought all 3 definitions of the function ok should work. But it appears only the last one works. It seems that there is something going on with the interaction of arrays and types that I don’t fully understand. Please help to explain the behavior and if there are “rules” to let me work out how it works. Thanks

using Nulls
function ok(A::Array{Union{T,Nulls.Null} where T <: Number}, B::Number)
  return 1
end
@which ok([1, null, 2],2)

function ok(A::Array{Union{Integer,Nulls.Null}}, B::Number)
  return 1
end
@which ok([1, null, 2],2)

function ok(A::Array{Union{Int64,Nulls.Null}}, B::Number)
  return 1
end
@which ok([1, null, 2],2)

#2

I suspect your y = x + 2 example is a bug. The machinery to deal efficiently with Union{T,Null} types is very recent and still a bit of a work in progress. Maybe @quinnj can confirm.

The method definition should read:

function ok(A::Array{Union{T,Nulls.Null}}, B::Number) where T <: Number
  return 1
end

This is fairly subtle and I don’t think I can explain it. But essentially the reason it was not dispatched to your method is:

julia> [1, null, 2] isa Array{Union{T,Nulls.Null} where T <: Number}                                                                                  
false                                                                                                                                                 

#3

Ok, I got it. So this works too:

julia> function okkk(A::Array{Union{T,Nulls.Null}} where  T<:Number, B::Number)
         return 1
       end                                                                                                                                            
okkk (generic function with 1 method)                                                                                                                 

julia> okkk([1,null],1)                                                                                                                               
1            

the reason is:

    julia> [1, null, 2] isa Array{Union{Nulls.Null,T} where T <: Number}                                                                                  
false                                                                                                                                                 

julia> [1, null, 2] isa Array{Union{Nulls.Null,T}} where T <: Number                                                                                  
true                                                                                                                                                  

The first is false because types in Julia are invariant (except Tuples), i.e. eltype([1, null, 2])<:Union{Nulls.Null,T} where T <: Number does not imply typeof([1, null, 2]) <: Array{Union{Nulls.Null,T} where T <: Number}. See https://docs.julialang.org/en/stable/manual/types/#Parametric-Composite-Types-1