Ricardo Iglesias
Ricardo Iglesias

Reputation: 655

Generic Numeric Arrays in Julia

I'm trying to learn Julia by reading the documentation, and they have code that looks like this:

function testFunction(x::Number)
    return x+5
end

This is a function that works for any of the many numeric types in Juila.

However, if I attempt to do something similar, like this:

function testFunction2(x::Array{Number})
    return x
end

I get the following error:

ERROR: MethodError: no method matching testFunction2(::Array{Int64,1})
Closest candidates are:
  testFunction2(::Array{Number,N} where N) at /Users/.../Desktop/Test.jl:45

Am I doing something wrong? I thought this: Array{Float64} is how you declare an array of a specific type, yet using a type like Number, which works for the regular case, doesn't work here... Any insight is appreciated.

Upvotes: 3

Views: 703

Answers (2)

Sundar R
Sundar R

Reputation: 14735

Adding to the other answer: the reason there is a difference in behaviour between the example in the manual and your code is that in your case, Number is used as the type parameter in another type (Array). That gets stricter type checks than if Number was used as the type by itself. As @StefanKarpinski says in this answer,

This is a consequence of parametric type invariance in Julia. See the chapter on types in the manual for more details.

(Link corrected to be current.)

The key point from the manual is: "even though Float64 <: Real we DO NOT have Point{Float64} <: Point{Real}." Similarly in your case, even though we have Int64 <: Number, we do not have Array{Int64} <: Array{Number}, which is why the type matching fails.

So in general, you can write x::Number to match any number type, you can write p::AbstractString to match any string type that's a subtype of AbstractString, etc. But if you're using the abstract type as a type parameter as part of another type, then you have to specify explicitly that you want it to match all subtypes of the parameter type i.e. with Point{<:Real} or Array{<:Number}.

Upvotes: 5

sujeet
sujeet

Reputation: 310

The definition

function testFunction2(x::Array{Number})
    return x
end

is the identify function that accepts as input an Array{Number}. So the following will work:

testFunction2(collect((1,3,-2.7,5+2im)))

but this will not work:

testFunction2([1,3,7,9])

This can be seen from here:

julia> typeof(collect((1,3,-2.7,5+2im)))
Array{Number,1}

julia> typeof([1,3,7,9])
Array{Int64,1}

The first matches the type of x in your definition of testFunction2 and the second does not. (Note that Array{Number} is synonymous for Array{Number,1}.)

What you are looking for is a function that accepts an array of any element type which is a subtype of Number. This is done as:

function testFunction2(x::Array{T}) where {T<:Number}
    return x
end

where now we have a parameter T that is allowed to be any subtype of Number. You also get to use the sugar

function testFunction2(x::Array{<:Number})
    return x
end

or even testFunction2(x::Array{<:Number}) = x.

Upvotes: 8

Related Questions