Confused by pass-by-sharing

In the following simple stylised script,

mutable struct P <: AbstractP 
    this 
    that
end

p = P()
...
sol1 = optimal(p)
q = p
p = add(p, something)  # p changed
sol2 = optimal(p)
p = q
sol3 = optimal(p)

would like that sol3 = sol1, but instead got sol3 = sol2. Unfortunatelly, it is still not clear what I should do to get the desired result, that sol3 = sol1? Many thanks!

The following line

q = p

just assigns a different name for p, thus if p changes later, q also changes. I think you need

q = copy(p)
4 Likes

Thank you for your reply. In my real use case copy didn’t work, got MethodError: no method matching copy(::P). But

q = deepcopy(p)

worked.

2 Likes

If the change in p happens inside a function, like bellow, I also need to do the assign of q to p in global scope (I think) so to have sol1 == sol3

...
sol1 = optimal(p)
function do(p)
    q = deepcopy(p)
    p = add(p, something)   # p changed
    sol = optimal(p)
    global p = q            # restore p 
    return sol
end
sol2 = do(p)
sol3 = optimal(p)

Is there a better way of doing all this? Thanks in advance!

That’s expected, because you need to decide what copying your struct actually means. In your case, that’s probably:

Base.copy(p::P) = P(copy(p.this), copy(p.that))

Sure–at the very least there’s no need to do the global p = q thing. Something like this should work without mutating global variables (which is almost always a code smell):

function foo(p)
  q = copy(p)
  add!(q, something)  # I'm assuming that your `add` function actually mutates its argument
  return optimal(q)
end

I’m assuming that your add function mutates its argument, which is why I’ve renamed it to add!. But I’m just guessing here because I can’t actually see your code.

Edit: Fixed some missing copy() calls in my copy definition

2 Likes