Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do Julia variables not exist in the scope of for-loops?

Tags:

julia

I am using Julia to do some basic integration estimation and am getting an UndefVarError with the following code:

using ExcelReaders
er = ExcelReaders

etInt = 0

waveLen = er.readxl("AM0AM1_5.xls", "Spectra!A3:A2004")
eT = er.readxl("AM0AM1_5.xls", "Spectra!B3:B2004")
gTilt = er.readxl("AM0AM1_5.xls", "Spectra!C3:C2004")
dirSol = er.readxl("AM0AM1_5.xls", "Spectra!D3:D2004")  

function trArea(r::Real, l::Real, v::Array, x::Int)
    return ((1/2) * (v[x] + v[x+1]) * (r-l))
end

for x in 1:length(waveLen)-1
    etInt += trArea(waveLen[x], waveLen[x+1], eT, x)
end

The error points to line 16. To my understanding, this means that etInt is undefined within the scope of the for-loop. Why is this the case with Julia?

like image 305
sh34v3 Avatar asked Jan 27 '19 02:01

sh34v3


1 Answers

To my understanding, this means that etInt is undefined within the scope of the for-loop.

Global variables do exist in all local scopes (such as a for-loop). However, from Julia version 1.0 on they are read-only in those local scopes. Write access to global variables must be made explicit.

To give a simple example, while

julia> x = 1       
1                  

julia> for i in 1:3
           @show x # only reading a global variable
       end         
x = 1              
x = 1              
x = 1              

works just fine,

julia> for i in 1:3
           x += 1 # writing to a global variable
           @show x
       end
ERROR: UndefVarError: x not defined
Stacktrace:
 [1] top-level scope at .\REPL[3]:2 [inlined]
 [2] top-level scope at .\none:0

doesn't work. This can be healed by putting an explicit global annotation:

julia> for i in 1:3
           global x += 1
           @show x
       end
x = 2
x = 3
x = 4

For more information, see the scoping section in the Julia documentation.

Note that people have complained about this a lot and it's actively being discussed on github and discourse (e.g. here and here).

Note that the effects of these scoping rules, like the potentially unintuitive error message that you're getting, really only hit you when you operate in a global scope (like the REPL). If you put everything in a function - any local scope - you get the expected behavior:

julia> function f()
           x = 1
           for i in 1:3
               x += 1 # no global necessary
               @show x
           end
           nothing
       end
f (generic function with 1 method)

julia> f()
x = 2
x = 3
x = 4

This is anyways what you should do to really get fast runtime as global variables are almost always bad for performance (see the Performance Tips).

Also notice that everything will work as expected in Jupyter notebooks using IJulia. The reason is that people are coming up with context dependent solutions as well, in this case SoftGlobalScope.jl. Something similar is/was being considered for the REPL. These are the main places where people work interactively.

So, to summarize, you can either just learn the scoping rules (which is dead simple) or you wait for some of the discussed "fixes" to land as has already been the case for jupyter notebooks.

like image 189
carstenbauer Avatar answered Nov 05 '22 20:11

carstenbauer