# Another possible solution to the global scope debacle

**URL:** <https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894>\
**Category:** Internals & Design\
**Created:** [October 4, 2018, 6:14pm UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894 "2018-10-04T18:14:07Z")\
**Posts on this page:** 20\
**Page:** 9

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [October 7, 2018, 7:22am UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/163 "2018-10-07T07:22:09Z")

</div>

> [@RoyiAvital](#):
>
> What I miss is the background story and the trade offs the designers considered.  
> For instance, why the current behavior chosen?

The issue was discussed at length, see eg

> <https://github.com/JuliaLang/julia/pull/19324>
>
> This PR examines the impact of deprecating (much of?) the distinction between ha…rd/soft scope. Instead it simply distinguishes between global and local scope. This means that all scope-blocks introduce the same type of scope (local), rather than distinguishing that toplevel functions have special, hard scope rules. I've updated the manual to try to show how this change would impact the user. The main change is that there would no longer be the concept of implicit globals computed from examining the module bindings. Instead the global/local computation would be purely syntactic. For example, take the following code snippet:
> 
> \`\`\`julia
> global x = 0
> for x = 1:10 end
> @show x
> \`\`\`
> 
> Under the current, this shows \`10\`, because \`x\` had a value before the for-loop.
> Under the new rules, this shows \`0\`, since the for-loop introduce a new local scope.
> 
> Making this code work as before would requiring declaring \`x\` to be a global inside the for-loop scope block:
> \`\`\`julia
> for x = 1:10; global x; end
> \`\`\`
> 
> Another option that this PR still permits is to make an assignment to x inside a begin/end block:
> \`\`\`julia
> begin
> x = 0
> for x = 1:10 end
> end
> @show x
> \`\`\`
> 
> The impact to base is small (two corrections to code that will be broken anyways when #265 is fixed).
> 
> The impact to tests is larger, as it takes a large number of unintentionally-global variables and causes them to emit a deprecation warning. I think the resulting changes are arguably beneficial, even if we don't decide to change the scoping rules, since they reduce the number of objects being kept around in global variables.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [October 7, 2018, 7:59am UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/164 "2018-10-07T07:59:54Z")

</div>

> [@JeffreySarnoff](#):
>
> being able to say [`local let ... end`](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/107) does seem like it would solve this problem.

I think the cure is getting worse than the disease. We went from a rule with complex subcases (soft scope, hard scope, etc) to a clean one which then some people found counterintuitive in some interactive contexts. Going back to special cases/constructs again may not be an improvement.

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [October 7, 2018, 8:45am UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/165 "2018-10-07T08:45:03Z")

</div>

Is there a branch with this proposed behaviour,  
I think I would really need to try it for a while to see how it feels.

Am I right is saying this would make more code act the same inside or outside a function?

---

<div class="post-metadata">

**Author:** ![leiteiro](https://avatars.discourse-cdn.com/v4/letter/l/b5e925/32.png) [@leiteiro](https://discourse.julialang.org/u/leiteiro)\
**Post date:** [October 7, 2018, 9:02am UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/166 "2018-10-07T09:02:29Z")

</div>

Frankly, I don’t think the discussion is about language design, but about how to accommodate instructors so that they don’t have to change their habits.

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [October 7, 2018, 9:10am UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/167 "2018-10-07T09:10:27Z")

</div>

> [@oxinabox](#):
>
> Am I right is saying this would make more code act the same inside or outside a function?

This is what I understand. The problem I had with this statement (given my examples at the beginning of this thread) is that beginners would start to think that **all code would act the same** which is not true. So essentially copy-pasting code from function body to global REPL is not safe anyway.

Other case of _not the same_ behavior is unintended overwriting of globals vs. failure to redefine a constant (due to the issue related to whether a function was evaluated or not in a global scope).

In other words: although the meaning of code under the proposed rule can be determined statically it is not possible to say statically if it will work or fail because it depends on the state of global REPL.

This is what I mean:

```julia
julia> for i in 1:10
       global cos = 10
       end

julia> cos
10

julia> sin
sin (generic function with 12 methods)

julia> for i in 1:10
       global sin = 10
       end
ERROR: cannot assign variable Base.sin from module Main

```

---

<div class="post-metadata">

**Author:** ![RoyiAvital](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/royiavital/32/571_2.png) [@RoyiAvital](https://discourse.julialang.org/u/RoyiAvital)\
**Post date:** [October 7, 2018, 9:28am UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/168 "2018-10-07T09:28:15Z")

</div>

> [@leiteiro](#):
>
> Frankly, I don’t think the discussion is about language design, but about how to accommodate instructors so that they don’t have to change their habits.

Couldn’t those problems be solved almost independently from each other?  
Namely the language by default will do what it right design wise yet it will also be flexible to allow building an environment (By loading package / One time defined macro) to satisfy demonstrators’ needs?

---

<div class="post-metadata">

**Author:** ![Rui](https://avatars.discourse-cdn.com/v4/letter/r/ba8739/32.png) [@Rui](https://discourse.julialang.org/u/Rui)\
**Post date:** [October 7, 2018, 10:32am UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/169 "2018-10-07T10:32:59Z")

</div>

You would only opt in when you are explicit, so it’s fine for new people. And it would be using a keyword that already exists, for the same kind of concept. Actually, I think it could end up simpler to understand than the proposed solution. Since in the proposed solution, I think you could only use “local” inside scoping blocks that are in global scope (it wouldn’t work inside an `if` but yes inside a `for`?). With `local` blocks, one could make it that `local` vars are never allowed in global scope. If you want it, just wrap the block in `local` and make explicit `globals` if necessary.

This is how I would ~ see one option, with the `local let` thing. If I’m confused, someone correct me:

1. Every bit of code is in either global or local scope. (like now)
2. Outermost stuff is by default global scope (like now)
3. Function contents (or blocks qualified with `local`) are in local scope
4. When in global scope, every variable is global (like now)
5. When in local scope, doing `x = ...` makes `x` a local var for the whole block. Unless it was somewhere qualified with `global`. (like now)
6. Scoping blocks (`for`, `let`, …, not `if` or `begin`s) in local scope, introduce a nested local scope. (like now)
7. Nested local scopes inherit their parent local scopes vars, unless marked with `local`. The new vars that didn’t exist, `x=...` belong just to them. (like now)

With the current proposal as is, one would have to remove the parentheses’ contents from 3. and add

1. Scoping blocks in global scope allow for marking variables with `local`

The current behaviour would require removing 3., and changing 6. to

1. Scoping blocks (functions, `for`, `let`, …, not `if` or `begin`s) always introduce a new (nested) local scope

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [October 7, 2018, 10:45am UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/170 "2018-10-07T10:45:24Z")

</div>

I wonder what the purpose of a “non-`local`” `let` is. What would we lose if `let` _always and everywhere_ introduced local scope to its contexts?

---

<div class="post-metadata">

**Author:** ![Rui](https://avatars.discourse-cdn.com/v4/letter/r/ba8739/32.png) [@Rui](https://discourse.julialang.org/u/Rui)\
**Post date:** [October 7, 2018, 10:49am UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/171 "2018-10-07T10:49:10Z")

</div>

At least

1. The more exceptions, the more complex it becomes
2. According to Jeff, `for` works like a repeated `let` so, making them behave differently feels to him like more special cases.
3. Making `for` default to local defeats the whole purpose of the proposal.

I wonder if 2. is only a core dev problem though, and as the viking said,

> [@StefanKarpinski](#):
>
> Putting the burden of knowledge on the more advanced user seems appropriate.

The new user can go without using `let` in global scope for a while I suppose.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [October 7, 2018, 11:26am UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/172 "2018-10-07T11:26:06Z")

</div>

Good point — if we maintain the equivalence of `for` with a transformation to `let`, then this is indeed the case.

The more I learn about the issue, the happier I am with the 1.0 choice (as is).

---

<div class="post-metadata">

**Author:** ![leiteiro](https://avatars.discourse-cdn.com/v4/letter/l/b5e925/32.png) [@leiteiro](https://discourse.julialang.org/u/leiteiro)\
**Post date:** [October 7, 2018, 12:02pm UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/173 "2018-10-07T12:02:54Z")

</div>

> [@RoyiAvital](#):
>
> Couldn’t those problems be solved almost independently from each other? Namely the language by default will do what it right design wise yet it will also be flexible to allow building an environment (By loading package / One time defined macro) to satisfy demonstrators’ needs?

That’s right, a categorical error about the type of problem, which hopefully we won’t all have to pay for.

---

<div class="post-metadata">

**Author:** ![ckoe-bccms](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ckoe-bccms/32/1816_2.png) [@ckoe-bccms](https://discourse.julialang.org/u/ckoe-bccms)\
**Post date:** [October 7, 2018, 12:11pm UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/174 "2018-10-07T12:11:53Z")

</div>

> [@RoyiAvital](#):
>
> Couldn’t those problems be solved almost independently from each other?  
> Namely the language by default will do what it right design wise yet it will also be flexible to allow building an environment (By loading package / One time defined macro) to satisfy demonstrators’ needs?

I believe that [https://github.com/JuliaLang/julia/issues/28789#issuecomment-414799023](https://github.com/JuliaLang/julia/issues/28789#issuecomment-414799023) was or is an attempt to do that ?

Ah, [here](https://github.com/stevengj/SoftGlobalScope.jl) it is.

---

<div class="post-metadata">

**Author:** ![hessammehr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hessammehr/32/3847_2.png) [@hessammehr](https://discourse.julialang.org/u/hessammehr)\
**Post date:** [October 7, 2018, 1:21pm UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/175 "2018-10-07T13:21:04Z")

</div>

Ditto for me. I find the current behaviour simple and consistent. I’m also a bit concerned about `let` blocks behaving differently inside vs. outside functions under the new rules:

```julia
function f()
    let x = 1
        y = x + 1
    end
    y # undefined
end

# versus
let x = 1
    y = x + 1
end
y # 2

```

---

<div class="post-metadata">

**Author:** ![NiclasMattsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/niclasmattsson/32/21988_2.png) [@NiclasMattsson](https://discourse.julialang.org/u/NiclasMattsson)\
**Post date:** [October 7, 2018, 1:50pm UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/176 "2018-10-07T13:50:22Z")

</div>

> [@leiteiro](#):
>
> Frankly, I don’t think the discussion is about language design, but about **how to accommodate instructors so that they don’t have to change their habits.**

> [@Stating my opininon](https://discourse.julialang.org/t/stating-my-opininon/15942/2):
>
> The “mistake” actually consisted of a positive change from a software engineering perspective. The behavior now is much more reliable in large source files and projects. Then it turned out that **some people really wanted to do lecture examples with certain 3-line loops in the REPL, and that became less convenient to the tune of _adding a single word_ to the code.**

I am one of these instructors who is arguing for a change in scoping behavior. For the record:

- For **my own personal use** of Julia, I really like the 1.0 scoping rules. They’re simple and consistent, and it’s easy to add a `global` keyword for interactive snippets in the REPL. I’m still a bit on the fence, but I may even prefer the 1.0 system over the proposal in this thread (again, for my own use).
- For **my teaching** , 1.0 scoping requires a bit of extra effort but is no great hardship. I can choose between taking a small detour to explain scoping up front, or I can punt and have the students use SoftGlobalScope.jl in the first sessions and explain why later.
- My **sole concern** in pushing this is that I think 1.0 scoping is too unintuitive for unchaperoned beginners, and I think it will significantly hurt their inital impression of the language and may even slow adoption rate long term. [Stefan also seems to be coming around to this view](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/160). I’m arguing for a change simply because I think my role as a teacher gives me a canary-in-a-coal-mine perspective that much more experienced Julia coders than I may lack.

Basically, please don’t ~~kill the messenger~~ misunderstand the message. We teachers are not griping about what we have to teach, we’re (or rather many of use are) worried about the confusion of our students.  
[EDIT: clarified last two sentences, thanks Tamas.]

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [October 7, 2018, 2:12pm UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/177 "2018-10-07T14:12:29Z")

</div>

> [@NiclasMattsson](#):
>
> Basically, please don’t kill the messenger.

I may misunderstand this, but I don’t think the tone was hostile at any point.

> [@NiclasMattsson](#):
>
> my role as a teacher gives me a canary-in-a-coal-mine perspective that much more experienced Julia coders than I may lack

Please keep in mind that many people here teach or taught programming to non-CS audiences, on both sides of this issue.

---

<div class="post-metadata">

**Author:** ![ckoe-bccms](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ckoe-bccms/32/1816_2.png) [@ckoe-bccms](https://discourse.julialang.org/u/ckoe-bccms)\
**Post date:** [October 7, 2018, 2:13pm UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/178 "2018-10-07T14:13:41Z")

</div>

> [@NiclasMattsson](#):
>
> My **sole concern** in pushing this is that I think 1.0 scoping is too unintuitive for unchaperoned beginners

I agree with your first two points. This last one is something which was suggested [here](https://github.com/JuliaLang/julia/issues/28789#issuecomment-414872850) to be solved by loading SoftGlobalScope.jl or similar by default. However, from what I understood from the discussion it is not clear to me if that would really solve everything or what pitfalls there might be with that approach and how this might interact with semantic versioning. I will await the result of the discussion and see what to do then.

---

<div class="post-metadata">

**Author:** ![turtle](https://avatars.discourse-cdn.com/v4/letter/t/ecb155/32.png) [@turtle](https://discourse.julialang.org/u/turtle)\
**Post date:** [October 7, 2018, 2:25pm UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/179 "2018-10-07T14:25:04Z")

</div>

Sorry, but I think this is not correct.

While the second `let` block returns the value 2 indeed,  
asking for `y` still gives `ERROR: UndefVarError: y not defined`

---

<div class="post-metadata">

**Author:** ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)\
**Post date:** [October 7, 2018, 5:31pm UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/180 "2018-10-07T17:31:13Z")

</div>

First of all, thank you @jeff.bezanson (and the other core devs of course) for spending a lot of time and effort on this issue.

Concerning feedback on the proposed solutions, I like that:

- It is very consistent and easy to explain. IIUC it says that: “things outside of functions are global unless marked as local explicitly”
- It is IMO quite intuitive for users novel to programming (as opposed to the naive but quite common “I have defined `x` here, why does it say it’s undefined?”)
- It only special cases functions, which is nice as they are arguably the most fundamental Julia construct

Things that could be added (already mentioned above):

- A fix to `for outer i = ...` in top level scope, now it errors
- `local for ...` and `local let ...` as in some cases the local default seems preferable (especially in “production code” or modules)

The second point is particularly relevant in a transition period as the warning would go from:

```nohighlight
In the future in top-level for blocks variable assignment will default to global.
Annotate all assignment explicitly as local or global.

```

to

```nohighlight
In the future in top-level for blocks variable assignment will default to global.
Use local for to retain the old behavior.

```

However it seems to me that this change is a bit drastic (especially as the proposed option hasn’t been tested yet) and I have the impression that is not necessarily an improvement in module code. For example, IIUC, with this proposal if I add a `for` loop at top level in a module, all the variables that I use will become global variables of the module and accessible from outside and I also risk to overwrite relevant globals that I am exporting.

With this in mind, I wonder whether the solution proposed in [this github comment](https://github.com/JuliaLang/julia/issues/28789#issuecomment-423346801) would be better: hard scope in modules (that are “production code”) and soft scope otherwise (scripts and REPL). The inconsistency may be annoying but by the time a user can write a module, I’m sure he/she can deal with this scope subtlety. In this scenario though what a “script” does when executed is a bit tricky to decide but one could opt in or out of this behavior by adding a line at the beginning of the file, say `softscope(true)` or something similar.

---

<div class="post-metadata">

**Author:** ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)\
**Post date:** [October 7, 2018, 5:37pm UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/181 "2018-10-07T17:37:44Z")

</div>

Concerning the wave of questions about this on discourse / slack / stack overflow etc., I wanted to point out that this could probably be reduced by a better error message. Right now one gets:

```julia
julia> x = 1
1

julia> for i = 1:10
       x = x + 1
       end
ERROR: UndefVarError: x not defined

```

Whereas something like:

`x inside the for loop refers to a local variable, use global x to modify global variable x`

would probably be better.

---

<div class="post-metadata">

**Author:** ![swissr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/swissr/32/208_2.png) [@swissr](https://discourse.julialang.org/u/swissr)\
**Post date:** [October 7, 2018, 6:14pm UTC](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/182 "2018-10-07T18:14:53Z")

</div>

This is what I have suggested in [my post](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/61). However in the meantime I think I have changed my mind and prefer the solution proposed in this thread:

- no `global` annotation needed, IJulia could drop the ‘automatically-insert-global-hack’ (hopefully I’m not wrong here, didn’t use IJulia in 1.0 yet). REPL doesn’t ‘need’ a similar ‘~hack’.
- no (?) other language has such scoping rules in the for loop (is this true?)
- no surprises (1. there was a [mention](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894/148) from a Matlab user at the breakfast table: you have to fix this – I think this is strong signal and bears weight, 2. there was a [‘bug report’](https://discourse.julialang.org/t/bug-with-julia-1-0-1/15964) exactly about this problem – another signal of unexpectedness)
- advanced users are more fit to declare what they want, i.e. write `local` when needed (`local for` is a cool idea, btw.)
- copy/paste from REPL to functions works right away without ‘global adjustment’
- former hard/soft scope complication is still solved

The only price is that the for scope is now global ([Edit]: maybe this is really bad, I’m not sure). – This said, I don’t feel competent enough to really state an opinion…

[Previous page](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894.md?page=8)

[Next page](https://discourse.julialang.org/t/another-possible-solution-to-the-global-scope-debacle/15894.md?page=10)
