Hey! I have been trying to make a saving macro to simplify my life and skip having to do the full saving syntax while keeping track of what I’m saving where. To do this, I have started writing a module. The main macro is as follows:
macro saving(funcname::String,params...)
quote
oldfile($funcname)
h5write($funcname*".h5","paramsNames",stringSymbolSeparator($params))
for (n,name) in enumerate(stringSymbolSeparator($params))
h5write($funcname*".h5",name,eval($(esc(params))[n]))
println("Saved $($(params)[n])")
end
end
end
Where the oldfile function just makes sure that there isn’t any file saved with funcname (and moves it to a .old file if it exists), and stringSymbolSeparator takes “params” as symbols and returns an array where each entry is the text used to write the variables (so that if I run @saving "test" var1, it will save the variable var1 in “test.h5” HDF5 file under the name of “var1”). When I try running the macro with variables that I have saved in the global scope it seems to work fine, my problem is that if I run the macro inside of a function, the eval command seems to be evaluating within the wrong scope and I get an UndefVarError. I’m pretty sure that the workaround has something to do with the macro hygiene, but after looking for a while I just can’t seem to fix it.
Thanks a lot for your help
Using eval() inside a macro is almost never necessary, and it’s almost always a signal that something has gone wrong. In this case, there’s no need for eval at all.
Rather than tackling the full version of your code, here’s a simple example of saving a single variable. First, I defined a stub h5write function so I don’t actually have to generate hdf files for testing:
julia> function h5write(filename, data, label)
println("saving: $data with label $label in file $filename")
end
h5write (generic function with 1 method)
Then I built a macro to call that function. Note the use of esc(param) to get the un-escaped variable in the expanded code, and the use of QuoteNode to turn a variable into a symbol giving the name of that variable:
julia> macro saving(name, param)
quote
h5write(string($name, ".h5"), $(esc(param)), string($(QuoteNode(param))))
end
end
@saving (macro with 1 method)
We can verify that this works at local scope:
julia> let
local_var = [1, 2, 3]
@saving "test" local_var
end
saving: [1, 2, 3] with label local_var in file test.h5
Perfect, thanks this helps a lot.
I still had some problems for implementing a for loop inside the macro to run over a variable number of parameters. In the end I ended just doing one part in a macro, and another part in a function and I have to write two lines instead of one. Still, it works like it should now.
Thanks again!