Write access to a variable in a module

module Mdl
b1 = false
end

import .Mdl.b1
julia> b1
false

julia> b1=true
ERROR: cannot assign a value to variable Mdl.b1 from module Main
Stacktrace:
 [1] top-level scope
   @ none:1

Why?

( I know, I can use a setter function for access)

1 Like

@eval Mdl b1=true works, but it may not be a good practice to modify variables in a module from another.

OK, @eval is another way for a write access. Mine was

function set_b1(x)
    global b1 = x
end

export set_b1

within Mdl .

But my question was “Why?”, the next one being “where is it documented?”

There are some rare situations where you want modules to be stateful. The Julian way about it seems to be to use Refs (like the Pkg global variables). You can imagine that using a ref makes changing the value a bit less complicated because the ref stays the same.

I don’t know whether the assignment of simple variables is unsupported due to complexity or what.

Example:

This is how you update a Ref value.

UPDATED_REGISTRY_THIS_SESSION[] = true

The “Why” isn’t made explicit in the documentation, but at the start it reads:

Modules are separate namespaces, each introducing a new global scope. This is useful, because it allows the same name to be used for different functions or global variables without conflict, as long as they are in separate modules.

This doesn’t explain explicitly why it isn’t straight forward allowed by just using

b1=true

or

Mdl.b1=true

But if it would be (silently) possible to do so, it is clear, that you could change a modules behaviour by accident just because you are setting a variable with the same name in your current scope. You may argue, that you have imported this variable explicitly, so you know what you do, but this may not always be the case, if there are more dependencies over serveral levels of different modules.

Well, I am on thin ice here with my reasoning, but if I have to decide for the implementation on this I would say, it’s better to have it seperated to avoid errors which are very difficult to debug.

1 Like

Still one more way to get a write access through encapsulation is using structs:


module Md2

Base.@kwdef mutable struct State
    b1::Bool = false
    b2::Bool = false
end

const st = State()
export st
end

using .Md2

julia> st.b1
false
julia> st.b1=true;
julia> st.b1
true

I personally would prefer this one from the point of view of readability, especially if the module contains more than one state variable.

Actually as realise now, my “why” could mean multiple things:

  • Is it documented somewhere explicitely?
  • Or does it implicitely follow from some documented behavior?
  • Why it was decided to implement it in this way (read-only access to global variables of other modules)?

It looks like the answer to the first two questions is negative. Would be nice to have it somehow in the documentation.

As to the the last question: I can generally understand both standpoints - “allow as much as possible” vs. “allow only what is necessary”. In this specific case, yes, I would argue this way:

but as there are workarounds, the issue ist not that important.