Correct way of modyfing argument


#1

Hello, I would like to write a function that is meant to run inside another function (or standalone), that modifies one of the variables of the namespace. An example would be:

k = 1

function dob(k)
   for i in 1:5
     k *= 2
   end
   return true
end

dob(k) # = 1, I would like it to be 32

I understand the behavior and why it doesn’t work. I wanted to ask what is the right way to do it. I could save the value in an object that gets passed as an argument to the function or I could request the global variable.

thanks


#2

You can pass a Ref (similar to a zero-dimensional array):

julia> k = Ref(1)
Base.RefValue{Int64}(1)

julia> function dob!(k) # the ! in the name is a convention, indicating an argument is modified
         k[] += 1
       end
dob! (generic function with 1 method)

julia> dob!(k)
2

julia> k[]
2

Mutating global variables is (a) slow in Julia and (b) generally considered bad practice because it makes the effects of your functions harder to understand, so I would not suggest using a global for this purpose.


#3

your function returns true regardless of the the value of the argument k, so you should use return k.

k = 1

function dob(k)
   for i in 1:5
     k *= 2
   end
   return k
end

Edit: Perhaps I misunderstood the question.


#4

Hello, I entered return true because my function returns something else that is no exactly what I want to modify. Should I return the value and catch it when running the function?. Is that the proper way?.


#5

Would it work if k is a vector?, the syntax k[] is quite weird.


#6
function dob(k)
   for i in 1:5
     k *= 2
   end
   return k
end

k=1
k=dob(k)

Now k has value 32. This is the preferred pattern for immutable object (like Int and any struct you define). For a mutable object like a vector you can do:

function foo!(v)
    v[1]=dob(v[1])
end
v=[1]
foo!(v)

Now v==[32]. Also you mentioned something about returning something else (not the thing you wanted to modify). In julia it is easy to return two values, eg

function bar(z)
    dob(z),true
end
z=1
z,success=bar(z)

Now z==32 and sucess==true


#7

You can do this by wrapping your scalar in Ref, but don’t. Don’t do this. Just return the new value from the function, and let the caller assign the result to the old variable (or not). This is cleaner, faster, and more composable.