How can i change variables of modules from other files or different modules?

Let’s say I got something like this:

module a
 global test = "hi"
end

# Another file
module b
 import a
 a.test = "bye" # ErrorException("cannot assign variables in other modules")
end

Looks like it’s impossible to change GLOBAL variables or variables in general from other modules which is very weird in my opinion, are there any alternative to this?

eval

Thank you, like this?

module a
 global test = "hi"
end

# Another file
module b
 import a
 @eval a.test = "bye" # ErrorException("cannot assign variables in other modules")
end

There may be another way using eval, but here are 2 ways:

julia> module a
        global test = Ref("hi")
       end
Main.a

julia> module b
        import Main.a
        a.test[] = "bye"
       end
Main.b

julia> a.test
Base.RefValue{String}("bye")

julia> module a
        global test = "hi"
        settest(t) = (global test = t)
       end
WARNING: replacing module a.
Main.a

julia> module b
        import Main.a
        a.settest("bye")
       end
WARNING: replacing module b.
Main.b

julia> a.test
"bye"

You can ignore the Main. if they are real packages.

4 Likes

Thank you very much, I got a question about the first way, what if I want to change from String to Dict? it will automatically error:
ERROR: MethodError: Cannot convert an object of type Dict{String,String} to an object of type String

Yes and this is probably a good thing! In Julia variables taking multiple types are frowned upon. You can do global test = Base.RefValue{Union{String, Dict{String, String}}}("hi"), but that will reduce the performance of your code. Also it is better if you make it a constant.

@eval a test = "bye"

3 Likes

Also it is better if you make it a constant.

What do you mean by that?

julia> const test = Base.RefValue{Union{String, Dict{String, String}}}("hi")
Base.RefValue{Union{Dict{String,String}, String}}("hi")

julia> test[] = "bye"
"bye"

julia> test = "bye"
ERROR: invalid redefinition of constant test
Stacktrace:
 [1] top-level scope at none:0

test can be a constant binding to a mutable object. So you can mutate the object it is bound to, but you cannot rebind it to another object. The second command is valid, the third is not, even if you try to bind it to another RefValue of the same type.

Oh alright so I guess the second way is valid and performs way better too, right?

Yes AFAIU, the constant Ref method I assume you mean.

No. If you can accept solution that require changes of module a, than using a const global ref is way better. This is especially true if the type is known.

Second method worked, thanks.