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?
In the case of ret3
, the type parameter is actually necessary because an Julia's type parameters are invariant. This is a bit of a subtle topic but the key fact is that while Array{Real}
is a type that can never be constructedFloat64 <: 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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With