# Clarify the documentation about modifying module variables

**URL:** <https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668>\
**Category:** New to Julia\
**Tags:** question, documentation\
**Created:** [February 3, 2024, 2:21pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668 "2024-02-03T14:21:16Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![benibilme](https://avatars.discourse-cdn.com/v4/letter/b/e5b9ba/32.png) [@benibilme](https://discourse.julialang.org/u/benibilme)\
**Post date:** [February 3, 2024, 2:21pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/1 "2024-02-03T14:21:16Z")

</div>

There is weird description without any example in the documentation.

[Julia 1.10 Global-Scope definition](https://docs.julialang.org/en/v1/manual/variables-and-scoping/#Global-Scope)

**Note that while variable bindings can be read externally, they can only be changed within the module to which they belong. As an escape hatch, you can always evaluate code inside that module to modify a variable; this guarantees, in particular, that module bindings cannot be modified externally by code that never calls `eval`.**

What does that mean? What are the mechanics? Why need an escape hatch?

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [February 3, 2024, 3:19pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/2 "2024-02-03T15:19:03Z")

</div>

I was going to say it means that the following does not work:

```julia
julia> module A

       data = 1

       function set_data(value)
           global data
           data = value
           return data
       end

       end
Main.A

julia> using .A

julia> A.data
1

julia> A.data = 2
2

```

Alas, it does work, which is very confusing (and maybe a bug???). ~~I’m pretty sure that if that module was in a proper package, it wouldn’t work.~~ Nope, still works, which contradicts what I thought I knew about Julia. So, thanks for asking the question!

Still, based on my current understanding, the “recommended” way of changing module data would be to use a function from inside the module, which can modify the data:

```julia
julia> A.set_data(3)
3

julia> A.data
3

```

And the “escape hatch”, if no such function is provided, is to use

```julia
julia> A.eval(:(data = 4))
4

```

Take this clarification with a grain of salt, since I seem to have some misconception here. I agree that the example given in the documentation itself is not very illuminating.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [February 3, 2024, 3:44pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/3 "2024-02-03T15:44:53Z")

</div>

> [@goerz](#):
>
> Alas, it does work, which is very confusing (and maybe a bug???)

Not a bug, so much as I think everyone forgot that section of the manual existed when [implement `setproperty!` for modules by simeonschaub · Pull Request #44231 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/44231) was written. So I think the docs just ought to be updated.

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [February 3, 2024, 5:59pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/4 "2024-02-03T17:59:55Z")

</div>

Huh. I totally missed this change in Julia 1.9!

I’m also not sure how I feel about it. I’ve been [relying on the old behavior to ensure module data can’t easily be set to an invalid value](https://github.com/JuliaQuantumControl/QuantumControlBase.jl/blob/c9fc2fee575caf504d92de709a728e6de5f63dd7/src/functionals.jl#L229-L237).

In any case, the documentation should definitely be updated:

> <https://github.com/JuliaLang/julia/pull/53170>
>
> As of Julia 1.9, bindings in modules can be changed directly.
> 
> See https://dis…course.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/3

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [February 3, 2024, 6:02pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/5 "2024-02-03T18:02:52Z")

</div>

It doesnt let you do anything you couldnt do before using `eval` so I dont think it’s really much to worry about (it’s a strict subset of `eval`s capabilities).

It’s just a special case that’s easy for us to optimize in a way that we cant optimize a fully general `eval`.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 3, 2024, 6:04pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/6 "2024-02-03T18:04:49Z")

</div>

> [@goerz](#):
>
> I’m also not sure how I feel about it. I’ve been [relying on the old behavior to ensure module data can’t easily be set to an invalid value](https://github.com/JuliaQuantumControl/QuantumControlBase.jl/blob/c9fc2fee575caf504d92de709a728e6de5f63dd7/src/functionals.jl#L229-L237).

I was also under the impression that reassigning globals from another module was just too dangerous to allow dot syntax until v1.9 came along and implemented it. We just have to use the typical practices instead: 1) making the variable non-public (this will be more formal with a `public` keyword in an upcoming version) and only exposing the getters and setters as public, 2) when possible, `const`ing the variable so even bad-faith users can’t reassign it.

---

<div class="post-metadata">

**Author:** ![benibilme](https://avatars.discourse-cdn.com/v4/letter/b/e5b9ba/32.png) [@benibilme](https://discourse.julialang.org/u/benibilme)\
**Post date:** [February 3, 2024, 6:04pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/7 "2024-02-03T18:04:52Z")

</div>

I still do not understand what is going on. Could someone interpret it for me? Does it mean that the global variables can be accessed with a `.` notatiton such as A.a?

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [February 3, 2024, 6:08pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/8 "2024-02-03T18:08:21Z")

</div>

> It doesnt let you do anything you couldnt do before using `eval`

Not if you’re determined, but an unsuspecting user is very likely to just set the (compltely invalid)

```julia
QuantumControlBase.DEFAULT_AD_FRAMEWORK = "Zygote"

```

as opposed to using the [`set_default_ad_framework`](https://juliaquantumcontrol.github.io/QuantumControl.jl/dev/api/quantum_control_reference/#QuantumControl.set_default_ad_framework) setter that ensures that `Zygote` is actually loaded and isn’t confused about the difference between a symbol and a string.

On the other hand, if they decide to use `eval`, I’d hope they understand that they’re leaving behind all pretenses of an official API, and any resulting breakage is on them.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 3, 2024, 6:08pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/9 "2024-02-03T18:08:27Z")

</div>

“calls `eval`” is just an off-hand mention, it doesn’t serve as an example like `A.eval(:(data = 4))`, as goerz said earlier, or `@eval A data = 4`. You’d have to look up `eval` to figure out these, so it’s normal not to immediately understand when you’re unfamiliar. Some passages are just dense with background information that reading comprehension slows to a crawl for anyone.

> [@benibilme](#):
>
> Does it mean that the global variables can be accessed with a `.` notatiton such as A.a?

Yep, you can test these yourself in the REPL.

```julia
julia> module A data=1 end
Main.A

julia> A.data=2
2

julia> A.data
2

```

The writing that says you can’t do this and must instead use `eval`, has been outdated since v1.9.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 3, 2024, 6:48pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/10 "2024-02-03T18:48:56Z")

</div>

> [@Benny](#):
>
> We just have to use the typical practices instead: 1) making the variable non-public (this will be more formal with a `public` keyword in an upcoming version) and only exposing the getters and setters as public, 2) when possible, `const`ing the variable so even bad-faith users can’t reassign it.

I would argue that constants should be declared with `const`, period. Relying on privacy to preserve an invariant is just security through obscurity, and it isn’t just users of the package which can modify a non-constant global. The compiler has to assume that the value can change at any time, which is inefficient. It’s only arguably “bad behavior” for a package user to change a variable, it’s variable! If the semantics don’t allow it to vary, don’t make it variable!

A package with global state which is expected to only be modified internally has a strong code smell. It means that the package can only be in one of those states at a time, and it means that whatever internal function modifies that state modifies it for all users of the package, including ones which were expecting it to be in state `A`, because it was, before something else put it in state `B`. Using dot-syntax to mutate that state directly is just a special case of this problem.

This isn’t a moral argument, one of my packages has some global state in the form of a (constant) Dict mapping symbols to behaviors. But I’ve taken pains to make sure that any unauthorized mutation of this Dict won’t break anything compiled against earlier, correct versions of it.

I suspect Julia will eventually add a `private` keyword which makes it arbitrarily difficult (if not impossible) to modify variables so marked from outside the package. If it’s important, one can use a gensym right now to make it very clear that something isn’t to be messed with. But none of these things will change the fact that global mutable state is nearly always a bad idea, especially if it’s load-bearing.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 3, 2024, 8:25pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/11 "2024-02-03T20:25:04Z")

</div>

Sure, keep invariants constant or immutable, but not everything is invariant, goerz provided a reasonable example. Julia lacks actual access modifiers in general, and my understanding is this gets out of people’s way when they need unrestrained access to implement controlled access. If someone breaks an instantiated module because they changed an internal unsafely against the public API, then that’s on them. Julia doesn’t stop you from breaking itself in other ways either, like adding or redefining Base methods on Base types. I would agree on the gensym, though that doesn’t stop reassignment and mutation either and I tend to just do underscore-led names. The upcoming `public` keyword does not seem to attempt to modify access, and I doubt a derivative `private` would do so either.

Also, could `Base.ImmutableDict` help your use case? You would have to specify all entries at instantiation, and if you need to progressively collect entries first, you could do that in a local scope with variables that go away.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 3, 2024, 8:55pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/12 "2024-02-03T20:55:28Z")

</div>

Yes, the converse applies: if something is genuinely variable, make it a variable. At which point it’s certainly not bad behavior for a user to modify it, that’s expected behavior, and a dot-syntax on modules is coherent with the rest of the language.

What isn’t good is mutable global state which isn’t resilient to mutation from outside the module. I’m trying to avoid being doctrinaire here, but that combination very often means that changing that global state will modify behavior from “upstream” of the change, and that’s a bad problem to have. The user setting that global to the wrong value is merely a special case of the problems which might arise.

`public` and `private` don’t have to carry the same semantics they carry in languages which get them from C++. Julia’s upcoming `public` is documentation, as I understand it, a way of marking something explicitly as part of the API without exporting it. It wouldn’t be needed if Julia didn’t have the `using` keyword, but it does, and in my opinion the convenience of `using` makes up for the problems it can cause.

`private`, if it’s ever added, can serve to prevent access to a variable outside of the defining module. The compiler could use that directive to eliminate the symbol entirely, so there’s no variable left to access, just compiled references to the memory it’s using. Whether this is philosophically compatible with Julia isn’t something I have an opinion on, but it’s definitely possible to add a feature like that.

I wish `ImmutableDict` were called something else, actually, like `AList`, because that’s what they are: a linked list of key/value pairs. Plenty of times that such a thing is useful, but it isn’t useful for my case, because adding a second definition of a key shadows the first. What I’d like is a Dict where redefining a key has no effect, Base doesn’t have one of those, and it’s not quite worth writing my own wrapper struct over Dict to provide that behavior. At the end of the day, it’s the user’s code once they load it, if they want to break it, I’m not strongly motivated to prevent them from doing so.

I would make it `private` as well as `const` if it were possible to do that, fwiw. it’s intended to be an append-only cache, which is only added to using a particular function, and if I could enforce that as an invariant, I would, it’s good practice.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 3, 2024, 9:14pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/13 "2024-02-03T21:14:12Z")

</div>

> [@mnemnion](#):
>
> Julia’s upcoming `public` is documentation, as I understand it, a way of marking something explicitly as part of the API without exporting it. It wouldn’t be needed if Julia didn’t have the `using` keyword

Traditionally, separate documentation was considered enough to inform what was public vs internal, but enough people felt this was unsatisfactory and should be indicated directly in the source code and discoverable by reflection functions. Whether a name was affected by `using` wasn’t much important; `export` lists are widely understood to be only a subset of public API.

> [@mnemnion](#):
>
> no variable left to access, just compiled references to the memory it’s using. Whether this is philosophically compatible with Julia isn’t something I have an opinion on, but it’s definitely possible to add a feature like that.

My understanding is that it isn’t, otherwise v0 would have provided true access modifiers for the much more widespread fields in addition to globals. Worth mentioning for OP that `getproperty` and `setproperty!` can be defined for a type to prevent dot syntax, but that doesn’t stop the core `getfield` and `setfield!`, or for modules `getglobal` and `setglobal!`. The implementation of dot syntax for global variables in modules seems to recognize that abusing dot syntax is generally just as bad as abusing those core functions or `eval`, so it’s unreasonable to gatekeep dot syntax only for modules.

It’s actually already possible to make a reference without a variable by interpolating instances into an expression, like `@eval getcache() = $(Dict())`. But that doesn’t generally stop bad-faith access because if _any_ method returns the interpolated mutable instance, you can mutate it. That topic is getting away from the thread topic so I’d suggest making a new thread or direct message if this continues further.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 3, 2024, 10:53pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/14 "2024-02-03T22:53:00Z")

</div>

> [@Benny](#):
>
> Traditionally, separate documentation was considered enough to inform what was public vs internal, but enough people felt this was unsatisfactory and should be indicated directly in the source code and discoverable by reflection functions. Whether a name was affected by `using` wasn’t much important; `export` lists are widely understood to be only a subset of public API.

To illustrate the connection, consider a counterfactual Julia in which `using` does not exist. Instead, names must be imported explicitly using `import`. Furthermore, only names which are on the `export` list can be imported: other names must be qualified with the module name.

This would prevent the issue which `using` poses, which is that adding a name to the `export` list can clash with names in modules which use the package, so a minor update can break downstream code, even without violating SemVer. This wouldn’t change the semantics of Mirror World Julia, all names from a module may still be accessed, they can be localized with `const foo = TheModule.foo` and what have you, but no global importing with `using`, and `import` only works on `export`.

Such a language would have no use for `public`, because the `export` list is the evident public API. You can’t break anyone else’s code by adding names to the `export` list, because `using` doesn’t exist, so neither do implicit imports. The _motive_ of `public` in actual Julia is that people actually use `using`, so there’s a desire to limit the export list to only the core features of a package, and have a second list of names which are officially supported in the API but aren’t imported automatically.

`using` is great for the REPL and the exploratory period of writing code, but it’s good practice to replace it with an explicit `import` list once things are settling into shape.

It’s quite tractable to write module code in which values intended to be private aren’t returned by any of the methods which use them, so if there were to be a `private` keyword, it would in practice protect those values from mutation outside of the module. I understand why a language might not want to provide this feature, but would make limited use of it were it present. I’ve dealt with the annoyance of deciding whether to modify some dependency to un-private a part of a class which I’d like access to, and for the most part, I don’t see the point in preventing people from burning their own fingers. I’ve also worked on codebases large enough to appreciate the ability to make it impossible to access certain state without explicitly modifying the code to do so.

---

<div class="post-metadata">

**Author:** ![benibilme](https://avatars.discourse-cdn.com/v4/letter/b/e5b9ba/32.png) [@benibilme](https://discourse.julialang.org/u/benibilme)\
**Post date:** [February 8, 2024, 1:22pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/15 "2024-02-08T13:22:00Z")

</div>

According to documentation, above code must be wrong as stated below. However, I tried it and it works. Possibly another out-of-date section in the documentation?

[Julia 1.10 module documentation Qualified Names Section](https://docs.julialang.org/en/v1/manual/modules/#Qualified-names)

Within a module, a variable name can be “reserved” without assigning to it by declaring it as global x. This prevents name conflicts for globals initialized after load time. The syntax `M.x = y` does not work to assign a global in another module; global assignment is always module-local.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 8, 2024, 5:39pm UTC](https://discourse.julialang.org/t/clarify-the-documentation-about-modifying-module-variables/109668/16 "2024-02-08T17:39:04Z")

</div>

> [@benibilme](#):
>
> The syntax `M.x = y` does not work to assign a global in another module; global assignment is always module-local.

Yes this sentence is outdated since v1.9
