recursionjuliamutablemutationmutual-recursion

Julia: Question about variable binding, mutating, and mutable functions


I am writing code in Julia which collects some output from a function foo (which mutates its input argument), and I'm trying to append the recursive evaluations from this function in an array A.

For instance, foo!(x) changes the value of x by adding 1 to each of its elements.

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


julia> x = [1, 1];

julia> foo!(x);

julia> x
2-element Array{Int64,1}:
 2
 2

I want to create an array A which stores the value of x = f(x) over a fixed range. However, A just ends up containing multiple copies of the final value of f(x), e.g.,

julia> x = [1, 1];

julia> A = [x];

julia> for i=1:3
           push!(A, foo!(x))
       end

julia> A
4-element Array{Array{Int64,1},1}:
 [4, 4]
 [4, 4]
 [4, 4]
 [4, 4]

I'm trying to get it to get it to efficiently output something similar to

julia> B
4-element Array{Array{Int64,1},1}:
 [1, 1]
 [2, 2]
 [3, 3]
 [4, 4]

I haven't been able to find a helpful resources for a developing a solid understanding of mutations, or the order in which mutations are executed in Julia. Any help in this regard would be greatly appreciated!


Solution

  • The way you've written it, you repeatedly push! the same object into A, which your foo! function mutates:

    julia> x = [1, 1]
    2-element Vector{Int64}:
     1
     1
    
    julia> A = [x]
    1-element Vector{Vector{Int64}}:
     [1, 1]
    
    julia> foo!(x)
    2-element Vector{Int64}:
     2
     2
    
    julia> A
    1-element Vector{Vector{Int64}}:
     [2, 2]
    

    One way of fixing this is to copy the elements in A before x gets mutated:

    julia> for i ∈ 1:3
               A[i] = copy(x)
               push!(A, foo!(x))
           end
    
    julia> A
    4-element Vector{Vector{Int64}}:
     [1, 1]
     [2, 2]
     [3, 3]
     [4, 4]
    

    A classic read on values vs. bindings can be found here.