Add new field to struct?

Hello!

Is there any way to add a field to an already defined struct? I have a case where I have no idea of how many fields I will need, so I would like to be able to do something similar to Matlab’s structs i.e:

MatlabStruct.NewField = "SomeValue"

Which will not work in Julia if “NewField” is not already defined in the struct. I would like to be able to do this some way since I prefer struct syntax much more than “Dicts” due to the “.” syntax instead of [“”], which gets quite cumbersome quickly (in my own opinion).

If it is possible to do what I want, I would like to know - if it is still not possible that is of course also an answer.

Kind regards

It’s not possible to dynamically add fields to a struct in Julia for a variety of mostly performance related reasons. However, if it’s only a question of syntax, dot overloading is available like this:

struct Foo
    properties::Dict{Symbol, Any}
end
Foo() = Foo(Dict{Symbol, Any}())

Base.getproperty(x::Foo, property::Symbol) = getfield(x, :properties)[property]
Base.setproperty!(x::Foo, property::Symbol, value) = getfield(x, :properties)[property] = value
Base.propertynames(x::Foo) = keys(getfield(x, :properties))

Now you can access the internal dictionary with dot syntax.

julia> x = Foo()
Foo(Dict{Symbol, Any}())

julia> x.a = 1
1

julia> x.a
1
6 Likes

Thanks for that Gunnar!

I have been searching for a while and just today I stumbled upon this: https://github.com/aminya/VarStructs.jl

Which seems to do what I actually want, even though it might not be best practice as you mention. Using a dict with the syntax you propose also seem like a good option, but that would mean I need to implement the Base get/set property for every custom Dict I define I suppose?

Now I am a bit closer to my goal none the less so thank you very much!

Kind regards

1 Like

Depending on what stuct features you want, NamedTuples may be a good fit:

x = (field_a = 1, b = "some string")
x = (; x..., field_c = 123.45)
2 Likes

Interesting usage of NamedTuples, I have not seen that before. Not what I want in this case though, thank you for teaching me something new still!

Kind regards

Doesn’t the VarStructs.jl package basically use the same idea as @GunnarFarneback? That is, it uses a Dict to map field names to field properties? Thank you.

1 Like

I just looked at the package and yes, it uses the same idea. It does add a couple of bells and whistles around it, most importantly a macro to create such structs and support for handling unset values and enforce types of the values. It also adds a bit of illusion that it actually creates a struct with the given fields rather than a wrapped Dict, but that won’t convince type inference. As long as you don’t expect more than it actually provides it should be fine to use it.

3 Likes

I will be using it mainly for a tool which allows a user to make basically a text document, so it should be fine, thanks! Especially since top performance is not a priority in the first write of the code, trying to go for convenience this time.

Could you explain the point with type inference with a bit more detail? Basically my understanding from your reply is that even though it appears as struct to me when working with it, the Julia compiler might not regard it as such and not be able to optimize it? I like to learn.

Kind regards

1 Like

If I am not mistaken, VarStructs are always mutable thus we cannot benefit from the performance of immutable structures?

This is a common question (one that I asked before also). There are a few ways to change structs when prototyping. Solutions range from Named Tuples (like above) to something like the following:

struct Foo1() 
   # fieldnames 
end
const Foo = Foo1

and then when you want to change the fields

struct Foo2() 
   # add new fields
end
const Foo = Foo2() # rebind 

I think the above is suggested by Revise.jl but can’t find it in their documentation.
You can also use ProtoStructs · Julia Packages or RedefStructs · JuliaHub

2 Likes

Thanks for your input! Nice to know these packages exist.

In my case it was not about prototyping, but making the data structure actually behave like a structure and being able to add fields at will. Here VarStructs.jl has proven quite useful.

The only thing which annoys me using VarStructs is that the auto-completion (i.e. TAB in REPL) does not show all the fields connected to the struct anymore. Wondering if there is any way to change that?

Kind regards

Hi!

This is because VarStructs.jl does not implement Base.propertynames() for the defined structures. If you add an implementation for this function as well, as @GunnarFarneback suggested, the Julia REPL will pick that up and autocomplete your field names. HTH!

That being said, you could just use a Dict with Symbol keys instead of tweaking structs for something which they were not really designed. In other words, do not add all that boilerplate to hide the behavior behind a struct-like interface, simply use the Dict API directly instead. All the more since this will make reading your code easier for others, who will probably not expect structs with dynamic fields.

1 Like