# Scope of variables inside functions, for loops, and if statments

**URL:** <https://discourse.julialang.org/t/scope-of-variables-inside-functions-for-loops-and-if-statments/38981>\
**Category:** General Usage\
**Created:** [May 7, 2020, 7:10pm UTC](https://discourse.julialang.org/t/scope-of-variables-inside-functions-for-loops-and-if-statments/38981 "2020-05-07T19:10:06Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![asb](https://avatars.discourse-cdn.com/v4/letter/a/87869e/32.png) [@asb](https://discourse.julialang.org/u/asb)\
**Post date:** [May 7, 2020, 7:10pm UTC](https://discourse.julialang.org/t/scope-of-variables-inside-functions-for-loops-and-if-statments/38981/1 "2020-05-07T19:10:06Z")

</div>

I don’t understand variable scope in Julia. I wrote a function to read some data files. The program reads nifti (a format for storing medical images) files inside a for loop. The data read is then returned to the calling program.  
Unfortunately, the data are of local scope inside the for loop (or the if statement), so I get an UndefVarError. I put global statements everywhere, and I still get the error.  
Note: I recently upgraded from Julia 1.3.1-1 to 1.4.1-1. The program worked before the upgrade.  
Here’s the code:  
make\_decmap.jl

```julia
using Images
using CSV
using NIfTI
using Glob
function read_amdt(dir)
wd=pwd();
cd(dir)
nii_files=glob("*nii",dir)
global dt
global am
for file in nii_files
    println(file)
    global dt
    global am
    if occursin(r"/[Dd][Tt].*nii",file)
        println("reading $file")
        global dt
        dt=niread(file)
        println(typeof(dt))
    end
    if occursin(r"/[Aa][Mm].*nii",file)
        println("reading $file")
        global am
        am=niread(file)
        println(typeof(am))
    end
    println(typeof(dt))
    println(typeof(am))
end
cd(wd)
return am,dt
end

```

Note: nifti image files end .nii  
Here are the commands I use in the REPL window, and julia’s output:

```julia
julia> dir="/mnt/data/PVP/philips/new_calib_test_data_temp_control_100518/asbUncor"
"/mnt/data/PVP/philips/new_calib_test_data_temp_control_100518/asbUncor"

julia> run(`ls $dir`)
AMu.nii DTu.nii EGu.nii EVu.nii FAu.nii test TRu.nii
Process(`ls /mnt/data/PVP/philips/new_calib_test_data_temp_control_100518/asbUncor`, ProcessExited(0))

julia> include("/mnt/data/julia/medical_imaging/make_decmap.jl")
make_decmap (generic function with 1 method)

julia> am,dt=read_amdt(dir)
/mnt/data/PVP/philips/new_calib_test_data_temp_control_100518/asbUncor/AMu.nii
reading /mnt/data/PVP/philips/new_calib_test_data_temp_control_100518/asbUncor/AMu.nii
NIVolume{Float32,3,Array{Int16,3}}
ERROR: UndefVarError: dt not defined
Stacktrace:
 [1] read_amdt(::String) at /mnt/data/julia/medical_imaging/make_decmap.jl:27
 [2] top-level scope at none:0

```

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [May 7, 2020, 7:14pm UTC](https://discourse.julialang.org/t/scope-of-variables-inside-functions-for-loops-and-if-statments/38981/2 "2020-05-07T19:14:55Z")

</div>

please format your code;

then, the `global` keyword is for accessing a global variable inside a function, for example:

```julia
a = 1
function main()
    global a
    a = 3
    return nothing
end

```

you can’t use `global` to create a global binding that didn’t exist before

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [May 7, 2020, 7:40pm UTC](https://discourse.julialang.org/t/scope-of-variables-inside-functions-for-loops-and-if-statments/38981/3 "2020-05-07T19:40:34Z")

</div>

Does your code even need `am` and `dt` to be defined in the outer scope?  
This should work fine:

```julia
function read_amdt(dir)
    wd = pwd()
    let am, dt
        try
            cd(dir)
            nii_files = glob("*nii",dir)
            for file in nii_files
                println(file)
                if occursin(r"/[Dd][Tt].*nii",file)
                    println("reading $file")
                    dt = niread(file)
                    println(typeof(dt))
                end
                if occursin(r"/[Aa][Mm].*nii",file)
                    println("reading $file")
                    am = niread(file)
                    println(typeof(am))
                end
                println(typeof(dt))
                println(typeof(am))
            end
        finally
            cd(wd)
        end
        return am, dt
    end
end

```

---

<div class="post-metadata">

**Author:** ![asb](https://avatars.discourse-cdn.com/v4/letter/a/87869e/32.png) [@asb](https://discourse.julialang.org/u/asb)\
**Post date:** [May 7, 2020, 8:56pm UTC](https://discourse.julialang.org/t/scope-of-variables-inside-functions-for-loops-and-if-statments/38981/4 "2020-05-07T20:56:02Z")

</div>

I got the program to work. I find the way julia handles the scope of variables quite unintuitive.

In every other language I’ve written code in, all variables defined in functions are local to the function unless declared as global (or included in a common block). I therefore expected the following code to work: (version 1)  
function read\_amdt(dir)  
wd=pwd();  
cd(dir)  
nii\_files=glob(“\*nii”,dir)  
cd(wd)  
for file in nii\_files  
if occursin(r"/[Dd][Tt].\*nii",file)  
dt=niread(file)  
end  
if occursin(r"/[Aa][Mm].\*nii",file)  
am=niread(file)  
end  
end  
return am,dt  
end

But this code throws the error  
ERROR: UndefVarError: dt not defined  
at the line  
return am,dt.

Variables defined in “for” loops are local to the “for” loop.  
To fix this, I added global statements inside the “for” loop.  
I interpreted the julia documentation on scope to mean that declaring a variable as “global” in a loop extends its scope to the context in which the “for” loop is embedded, so in this case it would be local to the function. So my next attempt included global statements inside the “for” loops: (version 2)

function read\_amdt(dir)  
wd=pwd();  
cd(dir)  
nii\_files=glob(“\*nii”,dir)  
cd(wd)  
for file in nii\_files  
if occursin(r"/[Dd][Tt].\*nii",file)  
global dt  
dt=niread(file)  
end  
if occursin(r"/[Aa][Mm].\*nii",file)  
global am  
am=niread(file)  
end  
end  
return am,dt  
end

This version doesn’t throw an error and does return the desired images, but the scope of dt and am is not restricted to the function, but is really global. So the function has the side effect of defining variables dt and am in the context in which the function is called. Executing  
out1,out2=read\_amdt(dir)  
not only sets variables out1 and out2 to the desired images, but also sets variables am and dt.  
Again, not the behavior I wanted or expected.

For my next attempt I added “local” statements after the function call: (version 3)  
function read\_amdt(dir)  
wd=pwd();  
cd(dir)  
nii\_files=glob(“\*nii”,dir)  
cd(wd)  
local am  
local dt  
for file in nii\_files  
if occursin(r"/[Dd][Tt].\*nii",file)  
global dt  
dt=niread(file)  
end  
if occursin(r"/[Aa][Mm].\*nii",file)  
global am  
am=niread(file)  
end  
end  
return am,dt  
end

This version failed to compile, throwing the error  
ERROR: LoadError: syntax: `global dt`: dt is a local variable in its enclosing scope.

I finally got a version to do what I expected by removing the global statements and keeping the local statements:(version 4)  
function read\_amdt(dir)  
wd=pwd();  
cd(dir)  
nii\_files=glob(“\*nii”,dir)  
cd(wd)  
local am  
local dt  
for file in nii\_files  
if occursin(r"/[Dd][Tt].\*nii",file)  
dt=niread(file)  
end  
if occursin(r"/[Aa][Mm].\*nii",file)  
am=niread(file)  
end  
end  
return am,dt  
end

I hope this posting will be helpful to someone else; I’m sure I’m not the only person who finds the way variable scope is handled in julia very confusing.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [May 7, 2020, 9:26pm UTC](https://discourse.julialang.org/t/scope-of-variables-inside-functions-for-loops-and-if-statments/38981/5 "2020-05-07T21:26:49Z")

</div>

> [@asb](#):
>
> I interpreted the julia documentation on scope to mean that declaring a variable as “global” in a loop extends its scope to the context in which the “for” loop is embedded, so in this case it would be local to the function.

Declaring something global makes it global, not local to the function. You can either use a `let` like @Vasily_Pisarev did or put `local am, dt` at the top of the function body to declare those variables in the outermost scope of the function instead of the loop body where they are assigned.

Please quote your code: [Please read: make it easier to help you - #11](https://discourse.julialang.org/t/psa-make-it-easier-to-help-you/14757/11)

---

<div class="post-metadata">

**Author:** ![asb](https://avatars.discourse-cdn.com/v4/letter/a/87869e/32.png) [@asb](https://discourse.julialang.org/u/asb)\
**Post date:** [May 8, 2020, 6:16am UTC](https://discourse.julialang.org/t/scope-of-variables-inside-functions-for-loops-and-if-statments/38981/6 "2020-05-08T06:16:46Z")

</div>

Thanks for your code sample. I didn’t know about let, try, and finally.  
I’m still not quite sure what the difference between try and local is.

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [May 8, 2020, 10:29am UTC](https://discourse.julialang.org/t/scope-of-variables-inside-functions-for-loops-and-if-statments/38981/7 "2020-05-08T10:29:55Z")

</div>

`try ... catch ... finally` is a way of dealing with operations that may throw an error.  
In your case, the function changes the directory, processes some files and then goes back to the original directory. `try ... finally cd(wd) end` ensures that it goes back to the initial directory even if it failed to read the files.  
More on that in the [Manual chapter on exception handlng](https://docs.julialang.org/en/v1/manual/control-flow/#Exception-Handling-1).  
Scope has its own [Manual chapter](https://docs.julialang.org/en/v1/manual/variables-and-scoping/) as well.
