What about initializing the immutable structure with the data from the mutable one?
For instance, something like:
DataA = quote
@eval struct A
@eval struct MutA
MutA() = MutA(0,0) # wandering if there is a better way to initialize these values as well
z = MutA()
z.a = 1
z.b = 2
w = A(expand(z)) # something like this
Where the expand function returns the list of values of z. For instance, this function does that, but it returns a string and thus the definition of w fails:
nfields = length(fieldnames(typeof(a)))
ifield = 0
list = ""
for field in fieldnames(typeof(a))
ifield = ifield + 1
if ifield < nfields
list = "$list$(@eval a.$field),"
list = "$list$(@eval a.$field)"
I understand that I could build explicitly a constructor, such as
A( x :: MutA ) = A( x.a, x.b )
but again, for structures with lots of fields that might become cumbersome.
The idea of having a mutable structure with the same data structure as the immutable one is that I need to read a lot of different parameters from a file, and then create an immutable structure with all that data. Thus, since the immutable structure has to be generated at once,
x = A(1,2,"abc", ... )
I need to create temporary variables for all the fields anyway, read all these temporary variables and, at the end, create the immutable x.
What I was thinking was to use a mutable structure with the same structure of the immutable one to read clearly and beautifully all the data, using something as:
y = MutA()
y.a = data
y.b = parse(Float64,somestring)
to finally initalize the immutable x variable, which will be used in performance critical code, using, as you suggest,
x = A(getfield.((y,),1:nfields(y))...)
Perhaps I am missing something trivial about immutable constructors which would turn out the task much easier?
Just to finish: I actually like the result obtained using the two structures, one mutable and the other not. Of course, it is only about how easy is to understand the code afterwards. But one example of the kind of thing I am aiming to use is:
AtomData = quote
index :: Int64
residue :: String
name :: String
x :: Float64
y :: Float64
z :: Float64
b :: Float64
occup :: Float64
@eval mutable struct ReadAtom
ReadAtom() = ReadAtom(0,"X","X",0.,0.,0.,0.,0.)
@eval struct Atom
Atom( atom :: ReadAtom ) = Atom([ getfield(atom,i) for i in 1:nfields(atom) ]...)
The only think I would like to improve here is the constructor for the mutable structure without parameters, which I still have to modify if I add an additional parameter to the AtomData list. Ideally I would like to provide default parameters already there.
The use of Parameters to initialize the values is what I want indeed.
However, using simply Atom() would not allow me to actually fill this variable
with the actual data (edit: using the names of the fields), which will be read afterwards from input files, since the Atom
structure is immutable.
But I completely understand that I could replace the mutable structure with a simple
list, or with a Dict. The choice relies only on how the code looks like. I like the idea of using
x = ReadAtom() # x is muttable and will be used for data reading
x.index = 1
x.name = "Carbon"
y = Atom(x) # y is immutable and will be used in critical code
Thank you very much for all your help. I learnt a lot of things.
An alternative way to initialize with default parameters a muttable struct, which is convenient in my case, is this:
function initdata(X :: DataType)
list = 
for type in X.types
if type == Int64
if type == String
if type == Float64
y = X(list...)
with which the actual code would look like:
x = initdata(ReadAtom) # muttable with default parameters
x.index = 1
x.name = "Carbon"
y = Atom(x) # immutable