Using `include` to bring variables into scope not working

My workflow is to usually have a init.jl file which brings some variables into scope, e.g. saveDir = "/path". Then all my scripts start with include("init.jl"). However, I noticed that this wasn’t always working, so I ended up doing global saveDir = "/path" (I know this is terrible practice, but hence the question).

I just tried to prove this to myself with a small example, but wasn’t able to get it to work. I thought it may have something to do with the fact that I ran include from a script and not the REPL, but I that wasn’t the case either. I feel like I couldn’t have imagined this behaviour - has anyone else experienced this? Or has an explanation for when and why this happens?

Perhaps you had include in a function, which indeed doesn’t work.

1 Like

Thanks! Would a loop be “equivalent” to a function? And if that’s the case, any ideas on how to circumvent that? My initial thought was to save a .jld2 file and then load it every time I needed it.

That’s exactly what I do to bring a set of predefined variables including large dicts into scope.

1 Like

You cannot include into any local scope.

If init.jl is defining some constant global variables, well, just do that globally. If the variables it define changes based on the caller, use a function instead.

1 Like

No, a global scope for loop should work. Eg

julia> @isdefined a
false

shell> cat /tmp/a.jl
a = 1

julia> for _ in 1
       include("/tmp/a.jl")
       end

julia> a
1
1 Like

by that definition it also works in a function…

Possibly related, I noticed that if you define functions which include variables you’ve defined globally then it uses those:

julia> a = 2
2

julia> silly_func(x) = a + x
silly_func (generic function with 1 method)

julia> silly_func(2)
4

Personally I found this really weird and annoying. Anyway, thank you all for the clarification, I think I’m just going to start using JLD2 files…

A good way to define parameters is to put them into a struct (or multiple structs) with Base.@kwdef.
The advantages are:

  • Usually no runtime costs (if struct is immutable and has concrete field types)
  • Default parameters are set in the code, but can be overwritten for specific use cases (e.g. tests) when constructing the parameter instance.
  • The struct can be loaded / saved the usual Julia ways

Apologies to re-open this, but I realised that this probably relates to another problem I have sometimes.

Often I define a parameter before entering a for loop:

important_param = 5
for i = 1:5
    x = i + important_param
end

However, sometimes (and for reasons I haven’t been able to fathom) julia complains that important_param is undefined, so I have to do this:

let important_param = 5
    for i = 1:5
        x = i + important_param
    end
end

This literally pops out of nowhere sometimes, and I assume it’s due to me misunderstanding how scoping works in Julia. Any ideas? Or should I look at / open another thread?

I have answered my own question, having found a bunch of threads on the issue e.g. this one. For my next project I will take the advice of writing everything in functions (though the claim that “The new debugger works like a charm” does not line up with my experience when I tried it back then). For now I’m going to keep putting global everywhere as if my life (or more realistically a deadline) depended on it.