An Issue in Defining a Mutating Function

This might sound a stupid question to experienced Julia users. When I define a simple mutating function as:

function foo!(x)
    x = x + 1
end

I expect the function to change the value of its argument. However when I execute the following:

x = 3
foo!(x)
x

the value of x is still 3. What’s going on here?

two things.

  1. Ints are immutable objects, so you can’t mutate them in any way
  2. Even if x was mutable (like an array), your method would not mutate it. All you are doing is assigning a new binding inside the function. The outer scope doesn’t know about that.

You might want to use a vector here.

function foo!(x)
    x[1] = x[1] + 1
end

x = [3]
foo!(x)
3 Likes

Ref is also a good option (and has slightly better performance):

julia> foo!(x) = x[] += 1
foo! (generic function with 1 method)

julia> x = Ref(3)
Base.RefValue{Int64}(3)

julia> foo!(x)
4

julia> x
Base.RefValue{Int64}(4)
2 Likes

If you want to mutate a global variable in a function, you should declare it to be global, or else all variables in your function will be treated as local variables. This works for your example:

julia> function foo!(x)
            global x += 1
        end
foo! (generic function with 1 method)

julia> x = 3
3

julia> foo!(x)
4

julia> x
4

Note that this violates the expectation of ! to mean that the function will mutate its argument:

julia> function foo!(x)
           global x += 1
       end
foo! (generic function with 1 method)

julia> x = 3
       foo!(x)
4

julia> y = 10
       foo!(y)
5

julia> y
10
1 Like

So would

julia> x::Int64 = 1
1

julia> function foo()
         global x += 1
       end
foo (generic function with 1 method)

julia> foo()
2

julia> foo()
3

julia> x
3

be a more standard way to do this?

This is not mutation either. That’s equivalent to

x = 1
x = 2

Which is not mutating, is assigning the label x to a new value.

Mutability is a property of the value, not of the label. And an Int is not mutable.

Concerning the original question, probably what the OP wants is

x = 1
f(x) = x + 1
# call reassigning x to the return value 
x = f(x)

(Although technically correct, I don’t think suggesting to use arrays or refs is actually what will solve the problem, and may lead to very bad initial programming habits and experience with Julia; this may help: Assignment and mutation · JuliaNotes.jl).

3 Likes