# Remove the soft scope altogether and make it global

**URL:** <https://discourse.julialang.org/t/remove-the-soft-scope-altogether-and-make-it-global/33333>\
**Category:** Internals & Design\
**Tags:** proposal, scope\
**Created:** [January 14, 2020, 6:41am UTC](https://discourse.julialang.org/t/remove-the-soft-scope-altogether-and-make-it-global/33333 "2020-01-14T06:41:45Z")\
**Posts on this page:** 10\
**Page:** 3

<div class="post-metadata">

**Author:** ![VivekTR](https://avatars.discourse-cdn.com/v4/letter/v/f475e1/32.png) [@VivekTR](https://discourse.julialang.org/u/VivekTR)\
**Post date:** [February 18, 2022, 12:29pm UTC](https://discourse.julialang.org/t/remove-the-soft-scope-altogether-and-make-it-global/33333/41 "2022-02-18T12:29:21Z")

</div>

Hi Benny,

I think I should clarify a little. I am not against having the option to `include` files. To this day I hate it that there is no include in HTML or JavaScript. If you write multiple scripts that access the global scopes, you know that you should be careful to avoid variable clashes, and convert some of them into functions. There is nothing wrong in writing multiple scripts as long as you are careful about the variable usages. There is an inherent risk in it which those who write are aware of. But because of hard scoping, I am having to redeclare all the variables in every `for` loop.

My point is it is a bad trade-off.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [February 18, 2022, 12:45pm UTC](https://discourse.julialang.org/t/remove-the-soft-scope-altogether-and-make-it-global/33333/42 "2022-02-18T12:45:15Z")

</div>

Revise is a fundamental tool in Julia development. And with some practice of the most convenient Julia development workflows the problems you are having with scopes will be a non-issue.

I think Julia has some early barriers that cause initial bad impressions. But those are by far compensated by the qualities, which one grasps with a little more experience. From that point of view of early and not-performance-critical prototype or scripting it has no advantage over other interpreted languages.

---

<div class="post-metadata">

**Author:** ![rfourquet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rfourquet/32/3610_2.png) [@rfourquet](https://discourse.julialang.org/u/rfourquet)\
**Post date:** [February 18, 2022, 12:45pm UTC](https://discourse.julialang.org/t/remove-the-soft-scope-altogether-and-make-it-global/33333/43 "2022-02-18T12:45:43Z")

</div>

> [@VivekTR](#):
>
> Please consider changing the scoping rules in v2.0+.

I would suggest experimenting a bit more with the current available options before holding your breath on v2.0, which will probably not change the scoping rules.

You mentioned `let` in one of your posts, doesn’t it work well for your workflow? like wrapping your entire script in a `let` block allows you to not have to insert `global` declarations.  
If you workflow involves `include`, an alternative is to use the `REPL.softscope` function:

```julia
import REPL
include(REPL.softscope, "script.jl")

```

At the command line, it could look like: `julia -e 'import REPL; include(REPL.softscope, "script.jl")'`

---

<div class="post-metadata">

**Author:** ![VivekTR](https://avatars.discourse-cdn.com/v4/letter/v/f475e1/32.png) [@VivekTR](https://discourse.julialang.org/u/VivekTR)\
**Post date:** [February 18, 2022, 1:03pm UTC](https://discourse.julialang.org/t/remove-the-soft-scope-altogether-and-make-it-global/33333/44 "2022-02-18T13:03:51Z")

</div>

Wow! This might be the one I need. Thank you!  
Btw, is there a way to enable soft-scoping by writing some statement at the beginning of a file?

`let` blocks delete all the variables after the `end` when running scripts. Makes it difficult to debug.

---

<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 18, 2022, 1:37pm UTC](https://discourse.julialang.org/t/remove-the-soft-scope-altogether-and-make-it-global/33333/45 "2022-02-18T13:37:02Z")

</div>

Containing code in functions is encouraged in Julia, too, so we seem to agree on the importance of having a local scope whose variables are local by default, isolated from the variables in the global scope. Then you are in effect proposing that `for`-loops shouldn’t introduce a new (local) scope, like `begin` and `if` blocks currently. That’s not an entirely bad approach, I know Python does it that way. However, that causes an infamously unintuitive issue with capturing variables, here’s a short Python example: `[f() for f in [lambda:i for i in range(3)] ]`; `[0, 1, 2]` is expected, but since `i` is not a new local variable per iteration, `[2, 2, 2]` is the result.

Besides, it means `for`-loops in global scopes are still susceptible to the locals-as-globals bug I described earlier. You’re right that being careful about variable clashes will still work, but it’s unreasonably hard to be so careful across a large project, especially with multiple people contributing (can’t read each other’s minds to avoid naming clashes).

When copying from a local scope, it really does just make more sense to paste it in a local scope (`let` block). For example, if you want to test out several code segments from different functions, you probably don’t want them to collide in the same global scope and have to restart the session. If you want to see what variables’ values are, you could do some `println`-debugging in your snippet, or you could put some `@debug` lines in your source code and “activate” their printouts (see Logging module in standard library), or you could use Debugger.jl for stepping and breakpoints.

---

<div class="post-metadata">

**Author:** ![rfourquet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rfourquet/32/3610_2.png) [@rfourquet](https://discourse.julialang.org/u/rfourquet)\
**Post date:** [February 18, 2022, 2:14pm UTC](https://discourse.julialang.org/t/remove-the-soft-scope-altogether-and-make-it-global/33333/46 "2022-02-18T14:14:57Z")

</div>

> [@VivekTR](#):
>
> is there a way to enable soft-scoping by writing some statement at the beginning of a file?

you can do something like:

```julia
# script.jl
import REPL

macro softscope(ex)
    esc(REPL.softscope(ex))
end

@softscope begin
    i = 1
    while i < 3
        println(i+=1)
    end
end

```

and in the REPL (no need to use two-arguments `include` anymore here) :

```julia
julia> include("script.jl")
2
3

julia> i
3

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [February 18, 2022, 2:22pm UTC](https://discourse.julialang.org/t/remove-the-soft-scope-altogether-and-make-it-global/33333/47 "2022-02-18T14:22:56Z")

</div>

I think those are possible options, but they derail a bit from the fact that there is a much better workflow. Here I have a file `test.jl`, which contains a function, which has the so discussed loop:

[![](https://global.discourse-cdn.com/julialang/original/3X/5/b/5bf78163d08f30fc9d4ede0ca06ae699527ca108.jpeg "Using Revise and the REPL soft scope in VSCode") ](https://www.youtube.com/watch?v=IOZLoM1wtv0)

Using `Revise` you can `includet("./test.jl")` (note the `t`) and track the changes to the file. Running the function after the change automatically tracks the code.

Additionally, you can select the code and copy/paste, or Control-Enter, into the REPL, and all that works because of the soft scope of the REPL.

All this may not be equal to what one is used in other languages, but it is convenient enough, maybe more in some aspects. With the additional bonus that the function in case can then be benchmarked with true production-time performance.

---

<div class="post-metadata">

**Author:** ![jlperla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlperla/32/34332_2.png) [@jlperla](https://discourse.julialang.org/u/jlperla)\
**Post date:** [February 18, 2022, 5:53pm UTC](https://discourse.julialang.org/t/remove-the-soft-scope-altogether-and-make-it-global/33333/48 "2022-02-18T17:53:43Z")

</div>

> [@VivekTR](#):
>
> Wow! This might be the one I need. Thank you!  
> Btw, is there a way to enable soft-scoping by writing some statement at the beginning of a file?

To make this even more confusing, as @pfitzseb said vscode also executes your `.jl` files with the softscope as you go through with the inline execution. Having code in `.jl` vs stored in a jupyter notebook is not sufficient to know what will happen in the scoping - especially during debugging/interactive use.

Essentially every usage (e.g. vscode inline, jupyter, repl, etc.) uses the softscope, which you find intuitive, EXCEPT including with `include("myscript")`. There were many legitimate reasons why the distinction was introduced but it has been slowly chipped away to make things more intuitive for most users. Nevertheless, at this point if you use loops in top level code you need to understand **how** the code is being executed to understand what the behavior would be. Copy/paste and file extension isn’t enough.

One way to deal with this is to primarily work in the vscode editor with `<shift-enter>` when testing and debugging, and then always make sure to wrap any loops in functions when you are done.

But the sooner you start wrapping any loops in functions the better, and for many reasons outside of this confusion. If you do, you will never hit this issue again. Regardless, if you ever put a `global` or an explicit `softscope` call in your code in the meantime, chances are you should rethink your workflow or code organization.

---

<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 18, 2022, 6:58pm UTC](https://discourse.julialang.org/t/remove-the-soft-scope-altogether-and-make-it-global/33333/49 "2022-02-18T18:58:10Z")

</div>

> [@VivekTR](#):
>
> How important is it to be able to copy code from scripts/REPL into functions. We care about debugging more than some microseconds of performance in scripts. Think about all the time it would take to delete and add globals

It’s not a question of performance but semantics. In version 1.0 of Julia, the soft scope for loops wasn’t applicable anywhere. Eventually, so many people whined about it that it was changed in the REPL for ease of use. However, Julia is committed to semantic versioning, which means that we don’t introduce new language changes that break old code if that code was using the language’s public, documented interfaces.

Switching julia to use a soft scope for loops could change the behaviour of old scripts written for version 1.0, so it was not allowed to make that change. It was decided that we could at least make the change in the REPL, but I think that was a bad compromise because it means that the language’s semantics depend on where you’re executing the code.

---

<div class="post-metadata">

**Author:** ![Leon\_Niceday](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/leon_niceday/32/216710_2.png) [@Leon\_Niceday](https://discourse.julialang.org/u/Leon_Niceday)\
**Post date:** [May 17, 2025, 5:03am UTC](https://discourse.julialang.org/t/remove-the-soft-scope-altogether-and-make-it-global/33333/50 "2025-05-17T05:03:15Z")

</div>

This post was temporarily hidden by the community for possibly being off-topic, unfocused, inappropriate, or spammy.

[Previous page](https://discourse.julialang.org/t/remove-the-soft-scope-altogether-and-make-it-global/33333.md?page=2)
