# Matrix{Float64}<:Matrix{Number} is false?

Why is `Matrix{Float64}<:Matrix{Number}` false?

search type invariance. TLDR is that they need different memory representations.

2 Likes

It also follows from the rules of concrete subtyping. `Matrix{Number}` is a concrete type that can be instantiated, and concrete types cannot have subtypes.

2 Likes

Try this:

``````Matrix{Float64} <: Matrix{<:Number}
``````
1 Like

In particular:

In other words, in the parlance of type theory, Julia’s type parameters are invariant, rather than being covariant (or even contravariant). This is for practical reasons: while any instance of `Point{Float64}` may conceptually be like an instance of `Point{Real}` as well, the two types have different representations in memory:

• An instance of `Point{Float64}` can be represented compactly and efficiently as an immediate pair of 64-bit values;
• An instance of `Point{Real}` must be able to hold any pair of instances of `Real`. Since objects that are instances of `Real` can be of arbitrary size and structure, in practice an instance of `Point{Real}` must be represented as a pair of pointers to individually allocated `Real` objects.

The efficiency gained by being able to store `Point{Float64}` objects with immediate values is magnified enormously in the case of arrays: an `Array{Float64}` can be stored as a contiguous memory block of 64-bit floating-point values, whereas an `Array{Real}` must be an array of pointers to individually allocated `Real` objects – which may well be boxed 64-bit floating-point values, but also might be arbitrarily large, complex objects, which are declared to be implementations of the `Real` abstract type.

3 Likes

Could you elaborate on this a bit more? I am confused by the syntax of `Matrix{<:Number}`

Invariance of type parameters means that e.g. `Matrix{Float64}` is not a subtype of `Matrix{Number}`, even if `Float64` is a subtype of `Number`. However, there exists “wildcard” type parameters in the form of `UnionAll` types. Typically such a `UnionAll` type is written with the `where` clause: `Matrix{T} where T<:Number`. It is an abstract type which has all `Matrix{T}` as subtypes where `T` is a subtype of `Number`. A short form is `Matrix{<:Number}`, which can be used if you do not need to use the type variable `T` elsewhere.

``````julia> dump(Matrix{<:Number})
UnionAll
var: TypeVar
name: Symbol #s3
lb: Union{}
ub: Number <: Any
body: Array{var"#s3"<:Number, 2} <: DenseArray{var"#s3"<:Number, 2}

julia> dump(Matrix{T} where T<:Number)
UnionAll
var: TypeVar
name: Symbol T
lb: Union{}
ub: Number <: Any
body: Array{T<:Number, 2} <: DenseArray{T<:Number, 2}
``````
1 Like

Beat me to it This was going to be my response:

As others have mentioned, `Matrix{Number}` is a concrete type, and one concrete type cannot subtype another concrete type.

`Matrix{<:Number}` is a union of types, and is shorthand for `Matrix{T} where {T<:Number}`.