Accessing a Vector of SVectors with 2 ranges -> Type instability

performance

#1

I am having the following difficulty:

using BenchmarkTools, StaticArrays

struct Dataset{D, T<:Number}
    data::Vector{SVector{D,T}}
end

data = Dataset([rand(SVector{3}) for i in 1:10000])

function Base.getindex(d::Dataset{D, T}, I::Range,
    J::Range) where {D,T}

    L = length(J)
    return Base.getindex(d, I, J, Val{L}())
end
function Base.getindex(d::Dataset{D, T}, I::Range,
    J::Range, ::Val{L}) where {D, T, L}

    sind::SVector{L, Int} = SVector{L, Int}(J)
    ret::Vector{SVector{L, T}} = Vector{SVector{L, T}}(length(I))
    i::Int = 1
    for k ∈ I
        ret[i] = d.data[k][sind]
        i += 1
    end
    return Dataset{L, T}(ret)
end

@btime $data[1:5, 1:2]
@btime $data[1:5, 1:2, Val{2}()]

  4.223 μs (4 allocations: 240 bytes)
  46.860 ns (2 allocations: 176 bytes)

I really cannot understand why the first call is 100 times slower, while the only thing it does is calculate a length and pass a Val.

I’d like some help understanding what is wrong. Of course, doing @code_warntype data[1:5, 1:2] tells me that the L variable is not inferred. But I don’t understand what else to do.


#2

Because at compile time the length of a general range is unknown, thus there is no way to know what L will be and therefore what method will be called is unknown so there will be dynamic dispatch. Pass in an SVector((1,2)) or something which has a type with a known length if you want to do something like this.