Julia: Arrays with abstract parameters cause errors but variables with abstract types don't

StackOverflow https://stackoverflow.com/questions/23326848

  •  10-07-2023
  •  | 
  •  

Question

The Julia style guide says the following:

Don’t use unnecessary static parameters. A function signature:

foo{T<:Real}(x::T) = ...

should be written as:

foo(x::Real) = ...

I expected that to apply to array parameters too. However, if I write the following code:

ret1(x::Real) = x
ret2(x::Array{Float64,2}) = x
ret3(x::Array{Real,2}) = x
ret1(1.0)
ret2(rand(2,2))
ret3(rand(2,2))

then I get the following console output (using Julia 0.2.1):

MethodError(ret3,(
2x2 Array{Float64,2}:
 0.841121  0.322133
 0.469432  0.495438,))

So why does Julia throw an error for arrays with abstract type parameters, but not for variables with abstract types?

Was it helpful?

Solution

In the case of ret3, the type parameter is actually necessary because an Array{Real} is a type that can never be constructed Julia's type parameters are invariant. This is a bit of a subtle topic but the key fact is that while Float64 <: Real is true, Array{Float64} <: Array{Real} is not. This is a bit confusing at first, but this is necessary for the compiler to be able to know the memory layout of function arguments when doing code generation. See the manual for more on this.

So you can dispatch on a Real as in ret1 because when you pass it a Float64, Float64 <: Real is true, whereas in ret3 you are passing it a Array{Float64}, and Array{Float64} <: Array{Real} is not the case, hence the no method error. To fix this, use a type parameter:

julia> ret3{T <: Real}(x::Array{T,2}) = x
ret3 (generic function with 2 methods)

julia> ret3(rand(2,2))
2x2 Array{Float64,2}:
 0.0857132  0.353194
 0.802737   0.717292

OTHER TIPS

In the case of ret3, a strictly Array{Real, 2} is expected, i.e., an array which can hold any kind of Real variables inside (while rand(2,2) is an array of Float64 only).

In this case the static parameter is not unnecessary:

ret3{T<:Real}(x::Array{T,2}) = x

As of julia 1.2, I believe the appropriate typing for ret3 is:

ret3(x::Array{<:Real,2})
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top