Effect of typing in structures

I have a package which contains a couple of structures that are essential to the package’s functionality. There has been a question of how to handle unknown/parametric types. Basically, to my knowledge, there are three alternatives:

# The struct contain a vector, but I do not define the subtype at all.
struct NamedVector
    values::Vector
    name::String
end

# The struct contain a vector, and I set it to `Any` (Edit: also promoting all input vectors to be `Vector{Any}`).
struct NamedVector
    values::Vector{Any}
    name::String
end

# The struct contain a vector, and I use a parametric type for it.
struct NamedVector{T}
    values::Vector{T}
    name::String
end

# Edit, I forgot that there should be a fourth one:
struct NamedVector{T}
    values::Vector{<:Any}
    name::String
end

(The struct I actually care about is a lot more complicated, but most fields where I have this issue are vectors)

To me, all of these would work (pass all of the tests I care about). However, I also want my code to be performant. For performance reasons, might there be reasons to prefer on over the other ones?

There is a section in the julia manual that touches on this: Performance Tips · The Julia Language

For most applications, your third version with NamedVector{T} is going to be the most performant if T is a concrete type (like Int, Float64, String, etc). If you want to put a bunch of different types into the vector, either of the first two are fine, though if performance is critical, this is not recommended.

3 Likes

If this version truly “passes all tests”, and you also truly care about performance, you have a bigger problem on your hands. This version only allows vectors whose type is exclusively Any. A Vector{Float64} won’t work. Yet, Vector{Any} is an unoptimized data structure that will provide you the worst possible performance from all Vector variants.

You probably need to go through your whole code base and check for type stability in many functions, not just for this particular type, as the input to this particular type is already type unstable. There are many tools in the Julia language to help you, but the simple @code_warntype will get you 90% of the way there.

1 Like

To do this in a test suite, I would rather use @test_opt from JET.jl, which can be automated (unlike @code_warntype where you need manual inspection).
The newly released DispatchDoctor.jl is also a splendid tool for this purpose.

2 Likes

Right now there is only one actual instance of Vector{Any}, however, here the types in it truly are (and should be Any). But even in situations where they are, it would be possible to simply promote the input to Any and use that (although as you say, this is not performant, which is exactly what I would like to try and figure out)