Make function which changes varriable

The example is pretty self-explanatory, I want to make a function which changes a variable. But it doesn’t work, how do I make it to?

a = 2
function change_a!(a)
    a = 3
    nothing
end
change_a!(a)
display(a);

the output is 2.
(I wish it was 3)

The keyword you’re looking for is global a, but this isn’t recommended (see: Avoid global variables). Using global variables often leads to confusing behaviour, bugs, performance problems and a plethora of other nastiness. Instead, simply return the value and assign it to a variable.

Note that containers (such as Vectors, Matrices) can be modified. This is because in that case you’re not modifying the outer variable itself, but the content that variable is wrapping.

If you’re coming from a different programming language, you might find Noteworthy differences from other programming languages helpful.

2 Likes

Or maybe, this is what you are looking for:

julia> a_ref=Ref(2)
Base.RefValue{Int64}(2)

julia> a_ref[]
2

julia> function self(ref_a)
       ref_a[]=4
       end
self (generic function with 1 method)

julia> self(a_ref)
4

julia> a_ref[]
4
2 Likes

I understand, thanks.
So this is appropriate code:

a = [2]
function change_a!(a)
    a[1] = 3
    nothing
end
change_a!(a)
display(a[1]);

is it, however, appropriate (since it was inappropriate to make a global?

This is better, since in change_a! you’re modifying the contents of the argument, not the global variable directly.

Note that global a would be used in change_a!, to tell the function to look in the containing scope for a instead of in the local scope. In both your original example and your second one, a is a global variable and also a local variable. See Scoping.

I’ll annotate global and localness here for you:

a = [2] # Declaring the variable `a` to point to an Array{Int,1} containing `2`
function change_a!(a) # change_a! has one argument named a
    a[1] = 3 # local a, set the first index equal to 3
    nothing
end
change_a!(a) # call change_a! with the global a
display(a[1]); # get the first index of the global a and display it

Still, the best approach would be having some sort of main or setup function that takes care of initialization of your variables and passes them to your inner work:

function change_element!(a)
    a[1] = 3
end

function main()
    a = [2]
    change_element!(a)
    display(a[1])
end

You would then call main() from the REPL.

1 Like

Thanks for the explanation. Also quite impressed by @oheil and whatever magic that is.

No magic at all:
https://docs.julialang.org/en/v1/base/c/#Core.Ref
It’s part of Julia’s interface calling to C.

A good read I found about the topic:

@Sukera 's array solution also mentioned and explained there.

1 Like

If you want to go the Ref or Array route, you’ll want to mark them as const (i.e., const a = Ref(2)) to somewhat avoid the performance cost of a maybe changing type (that’s the problem with globals). You will still have some overhead though because you have to dereference them - there’s no shortcut here. You might also have race conditions if you multithread your code, which is why it’s easiest and best to avoid them from the beginning.

1 Like

Perhaps it is worth mentinoning that:

  1. Scalars cannot be changed by default. They are immutable values. You can change, however, the value associated with the label a, and to do so you you better return the value from your function:
function foo(a)
    a = a + 1
    return a
end

and then call this function with

a = foo(a)

From a user perspective, this will change the value associated to a in the scope where the function was called from. This does not mean that the “previous a” has changed, but the value associated to the label a is another one now.

  1. Arrays can be changed, they are mutable. And that is why your example with a=[2] works. This is fine to do, but generally it is thought to be used for larger arrays, because there is where “changing” the values in the same position in memory is worth relative to just copying the values.
3 Likes

Again late, but let shamelessly point out my post about how you should not see variables as boxes to complement what Leandro is saying.

4 Likes