# SoftGlobalScope [![Build Status](https://travis-ci.org/stevengj/SoftGlobalScope.jl.svg?branch=master)](https://travis-ci.org/stevengj/SoftGlobalScope.jl) SoftGlobalScope is a package for the [Julia language](http://julialang.org/) that simplifies the [variable scoping rules](https://docs.julialang.org/en/stable/manual/variables-and-scoping/) for code in *global* scope. It is intended for interactive shells (the REPL, [IJulia](https://github.com/JuliaLang/IJulia.jl), etcetera) to make it easier to work interactively with Julia, especially for beginners. In particular, SoftGlobalScope provides a function `softscope` that can transform Julia code from using the default "hard" scoping rules to simpler "soft" scoping rules in global scope only. In Julia 1.5, "soft scoping" [became the default](https://github.com/JuliaLang/julia/pull/33864) for the built-in Julia REPL, and the SoftGlobalScope module simply calls through to the standard-library `REPL.softscope` function. The advantage of using the SoftGlobalScope library is that it also works with previous Julia versions. ## Hard and soft global scopes [Starting in Julia 0.7](https://github.com/JuliaLang/julia/pull/19324), when you *assign to* global variables in the context of an inner scope (a `for` loop or a `let` statement) you need to explicitly declare the variable as `global` in order to distinguish it from declaring a new variable. We refer to this as "hard" scoping rules. For example, the following code gives an warning in 0.7: ```jl julia> s = 0 0 julia> for i = 1:10 s = s + i end ┌ Warning: Deprecated syntax `implicit assignment to global variable `s``. └ Use `global s` instead. ``` and an error in Julia 1.0: ```jl julia> s = 0 0 julia> for i = 1:10 s = s + i # wrong: defines a new local variable s end ERROR: UndefVarError: s not defined ``` To make it work in 1.0, you need a `global` declaration: ```jl julia> for i = 1:10 global s = s + i end julia> s # should be 1 + 2 + ⋯ + 10 = 55 55 ``` This only applies to *global* variables; similar code *inside a function* (or whenever `s` is a *local* variable) works fine without any added keyword: ```jl julia> function f(n) s = 0 for i = 1:n s = s + i end return s end f (generic function with 1 method) julia> f(10) 55 ``` There were [various reasons](https://github.com/JuliaLang/julia/pull/19324) for this scoping rule, e.g. to facilitate [static analysis](https://en.wikipedia.org/wiki/Static_program_analysis) by the compiler, and it isn't too onerous in "serious" Julia code where [little code executes in global scope](https://docs.julialang.org/en/stable/manual/performance-tips/#Avoid-global-variables-1). However, for *interactive* use, especially for new users, the necessity of the `global` keyword, and the difference between code in local and global scopes, [can be confusing](https://github.com/JuliaLang/julia/issues/28789) and was [ultimately reverted](https://github.com/JuliaLang/julia/pull/33864). The SoftGlobalScope package exists to make it easier for *interactive shells* to automatically insert the `global` keyword in common cases, what we term "soft" global scope. ## Usage The `SoftGlobalScope` module exports two functions `softscope` and `softscope_include_string`, and a macro `@softscope`: You can transform the expression using `softscope(module, expression)` to automatically insert the necessary `global` keyword. For example, assuming that the module `Main` has a global variable `s` (as above), you can do: ```jl julia> softscope(Main, :(for i = 1:10 s += i end)) :(for i = 1:10 #= REPL[3]:2 =# global s += i end) ``` You can then execute the statement with `eval`. Alternatively, you can decorate the expression with the `@softscope` macro: ```jl julia> s = 0; julia> @softscope for i = 1:10 s += i end julia> s 55 ``` This macro should only be used in the global scope (e.g., via the REPL); using this macro within a function is likely to lead to unintended consequences. You can execute an entire sequence of statements using "soft" global scoping rules via `softscope_include_string(module, string, filename="string")`: ```jl julia> softscope_include_string(Main, """ s = 0 for i = 1:10 s += i end s """) 55 ``` (This function works like `include_string`, returning the value of the last evaluated expression.) In Julia 0.6, no code transformations are required, so `softscope` returns the original expression and `softscope_include_string` is equivalent to `include_string`. In Julia 1.5, `softscope_include_string(m, x)` is equivalent to `include_string(REPL.softscope, m, x)` using the `softscope` transformation function provided by Julia's `REPL` standard library. ## Contact SoftGlobalScope was written by [Steven G. Johnson](http://math.mit.edu/~stevenj/) and is free/open-source software under the [MIT/Expat license](LICENSE.md). Please file bug reports and feature requests at the [SoftGlobalScope github page](https://github.com/stevengj/SoftGlobalScope.jl).