Hey there,
I am trying to leverage Julia’s type system to get as many compile time protections as I can while still being performant. I’m using static arrays of reals for a project. Say I have a function f1 which can take an array a, and perform some operation on it once a has been sorted. Is it possible to create a subtype of Array which represents a sorted array? Then f1 in use might look like
function sorted(a :: Array{Real}) :: SortedArray{Real}
...
end
function f1(a :: SortedArray{Real})
...
end
# so that this fails since it's not guaranteed sorted
f1(a)
# but this works
f1(sorted(a))
In a similar spirit, I am working with 3D vectors represented like SVector{3, N} where N, it’d be awesome if I could define functions which only accepted normalized vectors (you can imagine the analogy in code).
For both cases, I could probably write a struct/wrapper around the array, but that brings two problems for me:
Will there be a performance hit?
Is there a neat way to ensure all functions which worked with the original type also work for the new type?
So, can I create a direct subtype of Array without changing the data representation underneath? Thanks for bearing with, I’m still learning Julia’s type system.
Right on @Tamas_Papp that’s pretty nearly exactly what I was looking for! Thanks!
I notice that the implementation does put the array containing your data inside a struct. I was interested to see what the impact would be on performance so I wrote the following test which measures time it takes to operate/allocate them (so the actual sort time is excluded). For very small collections (size 2-4), it’s at least 4x slower, and for larger ones (size 1024) the performance is closer (30% slower).
using SortedVectors
for log_size in 1:10
size = 1 << log_size
println("size = ", size)
# standard vectors
collection_1 :: Vector{Vector{Float64}} = []
for i in 1: size
push!(collection_1, Vector(rand(size)))
end
@time reduce(+, collection_1)
# SortedVectors
collection_2 :: Vector{SortedVector{Float64}} = []
for i in 1: size
push!(collection_2, SortedVector(SortedVectors.AssumeSorted(), <, sort!(rand(size))))
end
@time reduce(+, collection_2)
println()
end
With that in mind, is there a way to achieve this such a subtyping without a container? Trying to work with normalized 3D vectors with an analogous implementation would be a pretty big penalty.
But to answer your last question, no: you cannot subtype a concrete type in Julia. Fortunately, the cost of a container should be infinitesimal or even zero in many cases, so I would try benchmarking more thoroughly before you give up on encapsulation.
Finally, if you actually have 3D vectors, you should definitely check out https://github.com/JuliaArrays/StaticArrays.jl . The performance benefit of using SVectors from StaticArrays can be immense, and they are ideal for representing 3D vectors.
@rdeits thanks for pointing out the better instrumentation - @btime did confirm a performance gap in this case.
As for using containers I’ll play around a bit more - whatever I make will definitely be based on StaticArrays, they clearly are the right tool for the job.