# Pass a 1-D view to a function defined for Array{Float,1}?

Hello,

I would like to pass a view of an `Array{Float64,1}` to a function defined for `Array{Float64,1}`, however I got a type-error by proceeding this way. Is there a generic type that includes `Array{Float64,1}` and its `SubArray{Float64,1,Array{Float64,1}`? I guess the answer will be yes but do I get the same performance for functions like `f` if I drop the type requirement on A?

Example:

``````A = rand(10)

function f(A::Array{Float64,1})
out =0.0
for i=1:size(A,1)
out +=exp(-A[i]^2)
end
return out
end

f(A)
f(view(A,1:5))
``````

MethodError: no method matching f(::SubArray{Float64,1,Array{Float64,1},Tuple{UnitRange{Int64}},true})
Closest candidates are:
f(!Matched::Array{Float64,1}) at In:4

Stacktrace:
 top-level scope at In:12

There is a really simple way to do this that will not have a performance impact:

``````function f(A)
out = zero(eltype(A))
for i=1:size(A,1)
out +=exp(-A[i]^2)
end
return out
end
``````

Note, you could also write this as

``````function f(A)
return sum(exp.(-A.^2))
end
``````

which imo is simpler and more readable.

2 Likes

Restricting the input type has no effect on performance. It is only used for method dispatch or, frequently in my case, making sure you aren’t being an idiot by submitting a 3D array to your function that expected a 1D array.

2 Likes

Why can I pass a view of an Array{Float64,1} to a constructor without issue and can’t evaluate the previous function for views?

``````struct MyStruct
A::Array{Float64,1}
end

MyStruct(view(randn(10),1:5))
``````

MyStruct([-0.8972133521449638, -1.147599141327517, 0.42325517918092387, -0.20243752151598818, 1.462572740440295])

There are a couple things happening here. First is that `1:5` is not an `Array` despite being an `AbstractArray`. An `AbstractArray` is anything that can be indexed into, and has a `size` (and is `<:AbstractArray`). An `Array` is a specific implementation. `Range`s for example only store 3 numbers, the start, step, and stop of the range and computes indexing lazily. Similarly a `view` of an `AbstractArray` is still an `AbstractArray`, but also is not an `Array`.

The reason `MyStruct(view(randn(10),1:5))` works is because the struct knows what type the field `A` has to be, and so will convert the input to match that type. This is unambiguous since there is only 1 type of `MyStruct`. Function dispatch, however never converts it’s arguments, and only uses types to determine which methods are applicable and most specific. As such, if you wanted to type this function, the best type for it would probably be something like
`function f(A::AbstractVector{<:Number})`

3 Likes

Each of the these suggestions have a problem:

``````function f(A)
out =0.0
for i=1:size(A,1)
out +=exp(-A[i]^2)
end
return out
end
``````

This is not type stable, though there is little impact on performance. However, it will return a `Float64` when the input is an array of `Float32`, for example.

This

``````function f(A)
return sum(exp.(-A.^2))
end
``````

allocates a temporary array, and is a bit slower for it.

This one seems to be both fast and gives you the right output type:

``````f(A) = sum(exp(-x^2) for x in A)
``````

To @mleprovost, just drop the type signature completely, and reintroduce it only if you need it for dispatch.

2 Likes

Good point, I fixed the type instability of the first example. The second does allocate an array, but given how clean it is, I still like it. It will also play nicer with GPU than the other versions. Do you know if there’s any chance that the transducer optimizations will make it so the allocation can be automatically elided in the future?

That would be really cool, and would further improve the awesomeness of broadcast, but I have no idea if it will happen.