Vector{Real}, Vector{Float64} MethodError

First, a bit of background. In Julia, there are no instances of abstract types. For example, typeof(1) == Int. Int is indeed a Real so 1 isa Real is true, however typeof(1) == Real is false. You can think of the type system as a directed acyclic graph in which the concrete types are the leaves.

If you have a Vector{Real}, this is a Vector the elements of which are Reals. However, they can be any concrete type which is descended from Real. So, for example you can have Real[1, 1.0], that is, a Vector with one element which is Int and another which is Float64. Because the container type is Vector{Real}, the compiler only knows that the elements are guaranteed to be Real, but it does not know what concrete type they are. They could be, Int, Float16, UInt8, who knows.

When you write Vector{<:Real} this is the union of all Vectors the elements of which are real, for example

julia> Vector{Real} <: Vector{<:Real}
true

julia> Vector{Int} <: Vector{<:Real}
true

julia> Vector{Float64} <: Vector{<:Real}
true

As should be becoming clear, it is “better” for performance reasons to have a Vector{Float64} than a Vector{Real} in which all of the elements happen to be Float64. This is because Vector{Float64} guarantees to the compiler that the elements are all Float64, whereas for Vector{Real} the elements can be any Real type.

So, back to the type signatures of functions. When you write Vector{Real} on an argument, you are requiring that the input be a Vector{Real} (perhaps confusingly, Vector{Real} is itself a concrete type, even though it has an abstract type as a parameter). In the vast majority of such instances, what you really want is to get a Vector the elements of which are Real. Yes, this could be Vector{Real}, but it can just as well be Vector{Int} or Vector{Float32} or Vector{BigFloat}. This is what Vector{<:Real} is telling it, the parameter of Vector must be a subtype of Real, but not necessarily equal to Real.

2 Likes