Allocations when writing to vectors in struct

I am parsing some data from file where one signal is composed or couple UInt8 glued together. I want to separate them into individual signals, so I did the following:

mutable struct Status
    one::Vector{<:Integer}
    two::Vector{<:Integer}
    three::Vector{<:Integer}
end

This is embedded into a bigger struct, everything is mutable. Then I have a code that initializes this struct and fills it up in a loop value by value.

function Status(length)
    one = Vector{UInt8}(undef, length)
    two = Vector{UInt8}(undef, length)
    three = Vector{UInt8}(undef, length)

    return Status(one, two, three)
end

function parse_status!(input, status, idx)
    status.one[idx] = input[3*idx+1]
    status.two[idx] = input[3*idx+2]
    status.three[idx] = input[3*idx+3]
end

sts = Status(20)

for i in 1:20
    parse_status!(input, sts, i)
end

This leads to allocations, curiously of type Int64 although all data is UInt8.

When I try this code outside of the whole context, it seems to not allocate (the initialzed struct is being passed into a chain of functions and at one point filled with the parse_status function).

I thought that maybe it has something to do with Julia not figuring out the types of containers, so I tried different ways to make it more explicit and making the Status struct parametric removed the allocations.

mutable struct Status{T<:Integer}
    one::Vector{T}
    two::Vector{T}
    three::Vector{T}
end

while I don’t mind parametrizing it, I don’t really need it for anything else.

So I am wondering - have I correctly identified the original problem? And is this solution reasonable (are there any downsides to parametrizing structs)?

You should absolutely parameterize the struct, unless you only need it for UInt8, since Vector{<:Integer} is an abstract type, which will cause allocations.

Also, the struct should not be mutable, if you only modify the member fields and not the struct itself. Just remove mutable.

1 Like

Thanks! I feel by now I should have figured it out by myself that Vector{<:Integer} is abstract, but this makes sense of what I was seeing.

As for mutable - are there downsides for it, if it’s not a performance critical code? And I understand it correctly, that this makes sense only if all fields are containers of some sort? Other stucts have String or numerical fields.

Only depends if you will create many of them of not, creating one will allocate the struct itself in the heap (it’s 1 allocation) I don’t think of any use that would be for you since all things inside are mutable. So as long you don’t make too much it’s not that bad just no idea why you would make it mutable.

If the struct had String or numerical values then yes mutable is interesting since you may wanna change those and they are immutable