Isn’t the changes below between the two different versions supposed to be “considered” as breaking?
JULIA 1.8
Doc says:
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 .
This happens:
julia> module A
a = 1 # a global in A's scope
end;
julia> A.a
1
julia> module E
import ..A # make module A available
A.a = 2 # throws below error
end;
ERROR: cannot assign variables in other modules
JULIA 1.9
Doc still says:
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 .
But this happens:
julia> module A
a = 1 # a global in A's scope
end;
julia> A.a
1
julia> module E
import ..A # make module A available
A.a = 2 # surprisingly, this throws no error
end;
julia> A.a
2
I honestly do not get your explanation. Can you please make it easy to understand?
Will I be correct if I assume because all module definitions with module implicitly contain definitions of eval and include, so module E can make such a change to A?
You’re showing that a piece of code used to throw an error, so no one is probably using it, because, well, that’s just throwing an error. Now the same piece of code does something useful. That’s hardly breaking anyone’s workflow since no one was likely using a non-working piece of code.
My words on “breaking” might be incorrect, which would be a result of me not understanding what this part of the doc means exactly:
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 .
The bolded part is where my confusion is probably coming from: does it mean implicitly calls eval or explicitly calls eval? Because I took that statement to mean “code that never calls evalexplicitly”.
I interpret it similar to you in that the documentation seems to still claim this should not work, though I have to agree with Mose in that it is unlikely to break any code since it errored before and I don’t see any reason to prefer the 1.8 behavior over the 1.9.
In the 1.9 documentation they removed the part
julia> module E
import ..A # make module A available
A.a = 2 # throws below error
end;
ERROR: cannot assign variables in other modules
of the example, which seems to reflect that this is now expected to work, though I feel like the sentence you brought up could probably also be updated in some way to reflect this change.
As far as I understand it is not a breaking change, since one was not able to write like this before in the modules - therefore no-one has a bug related to this.
Now that it is possible, it is a “change”. For better or worse depends on who you ask.
I would love to update it, but seems I’m still not clear on the direction, so maybe someone who understands should.
For those who say it’s not breaking, well that is true in the real technical sense of what “breaking” is. But this not being possible in Julia 1.8, has led one into teaching and writing code the other way, something that could have been easy to do with the now Julia 1.9 behaviour: that was what I meant by “breaking”, so moderators can change the article title to what it best represents.
I just thought the eval was a thing to module as I explained above with module, but it seems as the doc points out in NEWS.md, modules can be modified anywhere. As an example:
julia> module A
a = 1
end
Main.A
julia> A.a
1
julia> function modify(A::Module, x)
A.a = x
end;
julia> modify(A, 10);
julia> A.a
10
So the line on the doc which says:
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 .
from what I understand, should be removed altogether.
Moreover, somehow the doc should also point just as is does under the section modules:
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.
Showing an example:
julia> module A
global a
a = 1
end
Main.A
julia> A.a
1
julia> function modify(A::Module, x)
A.a = x
end;
julia> modify(A, a);
ERROR: UndefVarError: `a` not defined