From "UndefVarError", a hopefully funny intro to Scoping

This is a translation version of the post from


by myself. Hope it’s not too boring.

First I declare that “Julia” refers to the language and is not associated with any person.

The lost toy - the “UndefVarError”

If one orders Julia to do something with this:

#Scoping
a=1
for i =1:20
    a+=1
end

then Julia will complain:

UndefVarError: a not defined
in top-level scope at base\none
in top-level scope at Scoping.jl:4

which is because of the position of the variable. Imagine that the entire program store variables in a “Global Scope”. Now, in human language, if Julia is or was a baby, such behavior is, of course, not a problem. In fact, when Julia was less than 0.6 versions old, the variable gets everywhere (in the Global scope) and the room is quite messy.

After the good old days parents decide more reasonable behavior be practiced. Therefore, a for loop that is directly written uses its small “box” for the “toys” (variables). This is to make things more organized and sometimes make it play more happily without spending forever finding and grabbing the toys from nowhere.

It is possible to read and get the value from inside a for loop. That says, it is possible to have a glance of the entire room when Julia is sitting in the toy box.

a=1
for i =1:20
    println("$a")
end

and it does not matter how many layers of boxes

x=1
for i = 1:10
    a=i^2
    println("a="*string(a))
    for j = 1:10
        println(i+j+a)
        println(x)
    end
end

But to physically reach it and do things to it, don’t stay in the box!

There are too solutions:

  1. step out, locate the toy in the big room.
a=1
for i = 1:20
    global a+=1
end
a

“global” is used to declare the operation. All happy.

However, if there is only one toy in the room, why sitting in an empty box? Why not create a larger box to include the poor toy(if I can afford cardboard)?

let
a=1
for i = 1:20
    a+=1
end
a
end

Use “let-end” block to let the variable in. “who cares about the empty one?”

The problems of let-end block

Then things go bad. If we can throw away the small boxes, who is in charge of tidying up the room??
Actually there were a lot of arguments…
Now don’t worry about this…


I said nothing.

Use of “local”

Alright let’s face it, Julia is growing up.

Considering 2 examples:

a=1
for i = 1:10
    global a = 1
    global a = a+i
    show(a)
end
a

a=1
for i = 1:10
    local a = 1
    local a = a+i
    show(a)
end
a

The local variable will only be used within its scope, whereas the brute “global” affect the global variable.
This seems unimportant, but this is about toy, who knows what weapons Julia will play with in the future?

Types of scopes, and how to be in charge

Now we gotta be careful about this:

There are mainly 3 types of scoping
global - global scope
function - function scope
for,while - soft scope
Why is it soft? Because “global” and “local” can break it!
function isolates its own set of variables, like a fancy version of organizer. To make it more fancy you can organize these organizers with modules and packages–but that’s too much for today’s story.

No global in functions!

So functions are special. They return values, but usually do not change it–unless the structure is complicated and when the parameter get passed by indices.

In functions, there is no need to write globals-- the parents are nicer here. And in fact, writing global will mean putting things into the global scope, which is not allowed (remember Julia’s cousin R did this and ended up in the hospital).

A function does not change this outer single value(when it is in a good temper).

function f(x)
    for i in 1:3
        x=x^2
    end
    return x
end

f(2)

But occasionally it gets mad.

the function times2() works without changing anything in the global scope here

x = [1 2;3 4]
x

function times2(x::Array)
    x*2
end

times2(x)
x

But its second brother times2!() gets quite angry

function times2!(x::Array)
    x[:,:] = x[:,:].*2
    return x
end
times2!(x)
x

If you run this, notice that it changes the x value outside.

But then how do I know if a function (or macro) is angry?

Note that they all have “!”

append!() sort!()
plot!() point()

if you don’t want to change the original value, use the peaceful version without “!”.

It is worthy to notice, that deleting the “!” does not calm this down

assigning a different variable name works neither, as it does not change the essential way that messages are passed.


function times2_2!(x::Array)
    y=x
    y[:,:] = x[:,:]*2
    return x
end

x
times2_2!(x)
x

This is useless.
In this case, maybe copy another version

function times2_3(x::Array)
    y = copy(x)
    y[:,:] *=2
    return y
end

x
times2_3(x)
x

A Quiz

Now, find the bug hidden in the toy

for i in 1:10
    for j in 1:10
        global a =i*j
    end
    if i*j>1
        show(1)
    end
end

See that?
Play with the toys, not the toy containers.

1 Like

The best place for these kind of posts if a blog — please consider starting one, and submit it to

then it will be aggregated in the RSS feed.

1 Like

Hi thanks for the suggestion. For this, if I start a blog, do I delete the origional post in the discussion and paste it onto the blog and then send the RSS feed?
Thanks in advance.

I was just suggesting a blog as the best place for future posts like this.

1 Like

OK. Got it. Thanks