I’m hitting one of these eval() scope-related issue, that I don’t know how to solve… maybe you can help me. This is related to an old Julia 0.6.2 code of mine, which was reading initial data from an external file, which contans lines like the following
x = 1.0
Nv = 10
which are initial values for some variables. Now inside my code I read the file, put every line in a string
record = "x = 1.0"
record = "Nv = 10"
and was evaluating that inside a computation function, with eval(parse(redord), eval(parse(redord) and so on and so forth for each record.
Now I’ve realized that since Julia 1.0 this is no longer possible, as eval works only in the global scope, and not inside a function. At this point, my code does not work anymore… So what would be a way to properly code this?
I mean, I have to read the file and evaluate each line it contains inside my function, but the story is that not every file contains the same variable initialization, other file my have lines like Nh = 50 and not refer to x or Nv above, so I do not know what variables should I initialize beforehand…
Any help? please? I need to read files containing assignations to variables, something I could easily do before the scope rules changed… Now that all these have changed, I can’t manage to read them.
I can’t change the input files either, as these come from a different project
I think the answer depends on the context.
Some ideas that come to my mind:
Just put everything in global scope:
x = 0
y = 0
z = 0
eval(Meta.parse("x = 1.0"))
f(x, y, z)
For that you need to have all the variables you can possibly need initialized first, otherwise the function call will fail. If there is nothing else in that file you can probably just do include(file).
If that’s too much clutter you can put the same thing inside a struct and update the values you read in.
Other option: create a bespoke function:
record = "x = 1"
expr = quote
# here you paste the records:
# here the calculation
return x * 2
I think if you can expand on what you exactly want to do it’s easier to recommend something specific.
Still the situation is a little bit more involved that including the file. The story is that this format files are inherited from old fortran, where there is a (very useful!) instruction called NAMELIST. In there you have a large file containing different records, one for each run, and separated by some END_OF_RECORD string. One such (simplified) file would be something like the following
Here we have three records, one the program must run three times, one for each record. At each run, only variables appearing in the record are updated, the other ones keep the same value they had in the preceding record.
I can not include the whole file at once, as only the last repeated values would be taken into account. I could split the file in three different ones, and run the code for each one, but then the calues in the previous records would not be inherited. Of course I could update the records will all the previous values, but that can be amazing for large input files.
That was easily handled with the eval(parse()) thing in previous julia versions, but not anymore. So the question is whether this functionality could be kept or recovered, now that eval() does not work on a local scope…
Well, I suggested two (or three, depending how you want to count) versions that do what you want. After the more detailed explanation I wouldn’t advise the second version but the first version (both that in the global scope as well as that with the struct) should work fine. What do you think about those?
Edit: What I mean with “the struct version”:
mutable struct A
A() = new(0, 0, 0)
a = A()
record = "x = 1"
n = split(record)
v = parse(Int, split(record)[end])
setproperty!(a, Symbol(n), v)
but that is what is was done originally, everything in glibal scope. But you need to loop over all lines in a record to eval() them, and that no longer works as the scope inside the loop is not yhe global one…
That’s what it was working in Julia 0.6.2, but not anymore
To nitpick eval has always only worked in the global scope. The difference is that global variables no longer are automatically in scope inside a function. If you know which variables are used in your computations you can just declare all of them global at the start of the function and the rest should work as in 0.6.
Thanks GunnarFarneback, but when decorating a variable with the global token, I have to give them a value, and that will override the value it had in the previous execution, while I only want that to happen in the set of variables I need to update, not in all of them…
Hi @Ferran_Mazzanti, did you figure out a solution to your problem? If you did, please post it in case others with similar problems see it (like myself ).
And regarding your main program – are you doing some kind of attribution analysis, changing one variable at a time to see the incremental impact on some output variable? I couldn’t quite follow your explanation in a previous post.