How to cleanly initialize structure with lots of members

I have a struct with lots of different members, all of which get initialized in a standard way. Currently, my code looks like

struct A
    a::Int
    b::Int
    c::Int
    function A()
        a = 1
        b = 1
        c = 1
        new(a, b, c)
    end
end

which looks fine for three variables, but if I had, say, 40 of them, then the final call to new() starts to look very ugly and I have to be very careful about where I enter in the variables. Is there any better way to do this, for example automatically initializing the struct based on the fact that the variable names in the constructor are the same as in the struct definition?

The Base.@kwdef macro might help here. It lets you give default values to members, and initialize them with keywords.

That being said, if you have 40 members in a struct, I wonder if you might want to use some other data structure instead, something you can loop/iterate over.

6 Likes

For such scenarios (where you have the defaults for your field values) is better to use the @kwdef approach (note that you no longer need to use new() for setting your defaults):

@kwdef struct A
    a::Int=1
    b::Int=1
    c::Int=1
    d::Int=2
end

This will generate a few constructors for you. Besides the default constructor you are also getting a keyword-based constructor.

Ways you can instantiate your A after defining your struct with @kwdef:

A()
A(b=3, d=5)
A(1,2,3,4)
2 Likes

Thanks! I’ll take a look at this macro. Unfortunately, for my particular context, I think the code is ultimately more readable if all the different entries are kept separate, as all their uses are quite different. I’ll think more about it though, as I share your discomfort with such an unwieldy structure.

You may want to consider GitHub - mauro3/Parameters.jl: Types with default field values, keyword constructors and (un-)pack macros which allows you write the default values inline with the fields.

Here is the example usage:

julia> using Parameters

julia> @with_kw struct A
           a::Int = 6
           b::Float64 = -1.1
           c::UInt8
       end

julia> A(c=4)
A
  a: 6
  b: -1.1
  c: 4

julia> A()
ERROR: Field 'c' has no default, supply it with keyword.

julia> A(c=4, a = 2)
A
  a: 2
  b: -1.1
  c: 4
1 Like

Note that this is also possible with Base.@kwdef, which removes a lot of the need for Parameters.jl these days.

2 Likes

With that many fields, I suspect that you should group them into multiple sub-types. A single struct with 40 plain primitive fields seems a bit alien to me.

2 Likes