I know it’s not for the lack of trying, but the manual’s section on scope is unclear if not outright wrong.
Issue 1
The manual says:
If you assign to an existing local, it always [emphasis not mine] updates that existing local: you can only shadow a local by explicitly declaring a new local in a nested scope with the local keyword.
a few lines below, it says:
When x = occurs in a local scope, Julia applies the following rules to decide what the expression means based on where the assignment expression occurs and what x already refers to at that location:
Existing local: If x is already a local variable, then the existing local x is assigned;
There are known exceptions to this:
module M
local x
let
x = 0
end
@assert x == 0 # errors. `x` is not defined
end
The exception is explained in a different section under the title “Global Scope”:
If a top-level expression contains a variable declaration with keyword local, then that variable is not accessible outside that expression.
Issue 2:
The manual says:
A scope nested inside another scope can “see” variables in all the outer scopes in which it is contained.
This is incorrect:
module A
x = 1
module B
global x
@assert !(@isdefined x)
end
end
Issue 3:
On soft scope, the manual says:
If x is not already a local variable and all of the scope constructs containing the assignment are soft scopes (loops, try/catch blocks, or struct blocks)… [and] if global x is defined… in interactive contexts (REPL, notebooks), the global variable x is assigned.
First, the condition “all of the scope constructs containing the assignment are soft scopes” can never hold because all scope constructs are always in some global scope. For instance, expressions evaluated in REPL are evaluated in the Main
module. But excusing this ambiguity, the instruction still does not hold. Evaluating the following in a REPL, the, the global x
is never defined:
module M
global x
for i in 0
x = i
end
@assert !(@isdefined x)
end
Issue 4:
The hard-vs-soft scope is a distinction relevant only to certain blocks (such as for ... end
) in the REPL. And it’s been felt before that the distinction has received undue emphasis Local scope rules are confusing in inner scopes (Julia 1.6) - #2 by jeff.bezanson . Yet, the manual pretty much starts off with hard-vs-soft scope.
Issue 5:
The manual is titled “Scope of Variables”, but it contains statements like:
the for loop body has its own scope
It is not always consistent about whether scope is the property of a variable or that of code blocks.
Issue 6:
The maual says:
Whereas assignments might reassign a new value to an existing value location, let always creates a new location.
This is not true:
let x
x = 0
let
x = 1 # does not create a new variable
end
@assert x == 1
end
Issue 7:
Is struct-end really soft scope?
global x
for i in 1:1
if true
x = 0
end
end
@assert x == 0
struct A
if true
x = 1
end
end
@assert x == 1 # errors
I think a better approach might be get users thinking about where in the code a variable is implicitly or explicitly declared, and to point out the distinction between variable declaration, variable assignment, and variable definition (declaration followed by assignment).
We may also want to draw a distinction between a variable’s scope and the block constructs (such as let ... end
blocks) that define the boundaries of variable scope. This gives us better language, and helps us avoid statements like “a global variable is accessible anywhere inside a global scope”, which is just not true:
module Outer
x = 0
module Inner
global x
@assert !(@isdefined x)
end
end
Here, the scope of the variable x
is not the entirity of the Outer
module.
The rest is just about global v local scope. Soft-scope can be explained as the exception, with motivation, once the rest of the content is covered.
The manual does contain a lot of important information including examples and the rational behind the soft-scope behavior, which I think should be kept. But I nevertheless started this shorter writeup which might serve as a starting point:
I was hoping folks here would review it, propose more examples, and point out any mistakes.