Understanding an argument-modifying function

I am using NLsolve to solve systems of nonlinear equations. Everything works fine, but I want to understand what this function does:

function f!(F, x)
    F[1]=x[1]^2+3*x[2]^2-9
    F[2]=17*x[2]-14*x[1]^2+49
end

f! appears to be a function which changes F but leaves x unchanged, and it assumes that both F and x are 2-tuples. Why, then, can I not say

a=(1.1,1.2)
b=(2.1,2.2)
f!(b,a)

? How would I pass a and b to f! such that b is modified in terms of a? If I do it, I get


MethodError: no method matching setindex!(::Tuple{Float64, Float64}, ::Float64, ::Int64)

Stacktrace:
 [1] f!(F::Tuple{Float64, Float64}, x::Tuple{Float64, Float64})
   @ Main ./In[94]:2
 [2] top-level scope
   @ In[103]:1
 [3] eval
   @ ./boot.jl:360 [inlined]
 [4] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
   @ Base ./loading.jl:1116

Tuples are immutable, the input F must be a vector, instead. (x can be a tuple, because it is not being mutated - but most likely will be a vector as well in the actual code).

julia> function f!(F, x)
           F[1]=x[1]^2+3*x[2]^2-9
           F[2]=17*x[2]-14*x[1]^2+49
       end
f! (generic function with 1 method)

julia> F = [1.1,1.2] # a vector
2-element Vector{Float64}:
 1.1
 1.2

julia> f!(F,(1,2))
69


2 Likes

Thank you! That’s exactly what I was looking for!