Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reassignment of Dictionary Values inside a Function in Julia

New to Julia and hence, likely a basic question.

x = 1
function someFn()
   print(x)
   x = 3 
end

This throws an error at print(x) because global x inside is not seen inside the function. This makes sense.

x = [1,2]
function someFn()
   print(x)
   x[1] = 4
end
print(x)

Here print(x) is able to see the global array x and x[1]=4 changes value of global x globally. A similar behavior is observed when I make x a dictionary.

Three questions

  1. Is this behavior of variable / array and its scope inside a function consistent how Julia should work?
  2. When x is an array, it is visible inside the function even without passing a reference as an input to function. Is this correct?
  3. Also, changing a value of an entry in the array is reflected globally. Is this so because Julia treats array x as a reference everywhere?
like image 952
Sundar Avatar asked Oct 16 '22 03:10

Sundar


1 Answers

Let me comment on my understanding of the issue.

First, variable names point to values. The most basic way to make a binding between the variable name and the value is assignment of the form:

variable_name = value

Note that it is crucial that on the left hand side of = the only thing that is present is variable name and nothing else.

(side note: apart from = there are other ways to make a binding, e.g. += etc. or function definitions; but let us focus here on the core of the issue)

Now if you see = this does not mean that it is an assignment that creates a new binding. In particular:

variable_name[index] = value

is not an assignment operation (that creates a new binding) but setindex! operation. Writing variable_name[index] = value is the same as writing setindex!(variable_name, value, index.

(side note: this is true except for some corner cases like e.g. handling of begin or end, handling by @view macro etc., but again this is not crucial in the discussion)

Now to directly answer your questions given these comments:

Is this behavior of variable / array and its scope inside a function consistent how Julia should work?

Yes. But note that you get an error in:

x = 1
function someFn()
   print(x)
   x = 3 
end

because Julia knows that x = 3 is present in the body of the function which makes Julia aware that x is a local variable even before it is bound to the value (a variable is either local or global).

Here is a more extreme example of the situation:

julia> x = 10
10

julia> function f()
       if true
           println(x)
       else
           x = 5
       end
       end
f (generic function with 1 method)

julia> f()
ERROR: UndefVarError: x not defined

although we know that the branch after else will never executed still it makes variable x to be local.

When x is an array, it is visible inside the function even without passing a reference as an input to function. Is this correct?

It is visible beause x[1] = 4 does not create a local variable named x but is simply a call to setindex! function. So there is no x variable defined locally, therefore a global variable x is used.

Also, changing a value of an entry in the array is reflected globally. Is this so because Julia treats array x as a reference everywhere?

Here be sure to remember that x is not an array. It is a variable that is bound to point to an array. Then, again, x[1] = 4 is the same as if you have written setindex!(x, 4, 1) so you simply call a function on a value (an array in this case) that a variable x is bound to. And this works, because scoping rules in Julia say that if there is no local variable of a given name in the scope Julia searches global scope for this name.

Finally let me comment that using global variables in Julia is discouraged as this is slow. So while this discussion is highly relevant to understand how Julia works, in practice you almost never need to know this (you will use local variables 99.99% of the time, and if you use global variables better make them const).

like image 74
Bogumił Kamiński Avatar answered Oct 22 '22 03:10

Bogumił Kamiński