If
Int64 <: Real
is true, and I presume Julia follows normal function typing rules (for dicts) where the “return” type can be more specific than indicated by the type annotation, why isn’t the following true?
Dict(:x=>[1,2], :y=>[1,2]) isa Dict{Symbol, Array{<:Real, 1}}
Do I need to do something like:
Dict(:x=>[1,2], :y=>[1,2]) isa <:Dict{Symbol, Array{Real, 1}}
to ‘ask the question’ properly?
Welcome!
In Julia, type parameters are invariant. So even though Int <: Real
it is not true that Array{Int} <: Array{Real}
.Your use-case is just another example of such type invariance.
julia> Int <: Real
true
julia> Array{Int} <: Array{Real}
false
You can read more about types here
https://docs.julialang.org/en/v1/manual/types/index.html#Parametric-Types-1
1 Like
What is happening here?
julia> [1,2] isa Array{<:Real,1}
true
and here?
julia> Array{Int} <: Array{<:Real}
true
Your last piece of code is equivalent to checking
julia> Array{Int} <: Array{T} where {T <: Real}
true
The RHS is the set of all types of the form Array{T} where {T<:Real}
. So, an element that belongs to Array{Int}
is also an element of Array{T} where {T<:Real}
. An element that belongs to Array{Float64}
is also an element of Array{T} where {T<:Real}
and so on
julia> Array{Float64} <: Array{T} where {T <: Real}
true
1 Like
So it seems like I can get the kind of type variance behavior that I intuitively want to use – returning to the original question, why doesn’t this “hack” work for the more complex type? :
julia> Dict{Symbol, Array{Int,1}} <: Dict{Symbol, Array{<:Real, 1}}
false
You need
julia> Dict{Symbol, Array{Int,1}} <: Dict{R, Array{T, 1}} where {R, T}
true
Thanks!
I see that
julia> Dict{Symbol, Array{Int,1}} <: Dict{Symbol, Array{T, 1}} where {T <: Real}
true
also works.
Is the way I am doing this not the “Julian” way to do things?
This is also fine and depends on whether you want to use a fixed type or its subset. What I wrote is slightly more generic because you can replace R
with any subtype of Symbol.
This is what you are doing with Array{T, 1} where {T<:Real}
as well. You are allowing the code to compile for a subtype of Real
so you have flexibility in that you can pass a subtype of Real
in place of T
like so
julia> Dict{Symbol, Array{Int,1}} <: Dict{Symbol, Array{T, 1}} where {T <: Real}
true
julia> Dict{Symbol, Array{Float64,1}} <: Dict{Symbol, Array{T, 1}} where {T <: Real}
true
There is nothing non-Julian in what you did but I like to keep my code as generic as possible Notice that keeping the code like Array{T, 1} where {T<:Real}
has no runtime penalty.
1 Like