[Closed] MXS Array and its deepcopy
Copy and Deep Copy have always being confused; and for some developers, never explained.
What does Copy do? and What does Deep Copy do? where to use copy and where deep copy? let’s see the difference:
Copy: just constructs a new object of your given, and then assigns all the referenced values of your given object.
Deep Copy, instead constructs a new object of your given, and also creates new object for each value, and nothing will be referenced. Their are 2 different object now, and not sharing anything.
As you may already know, many Autodesk products (including 3DS Max and Maya) can be coded using Python. I believe that this copy and deep copy comes from Python.
Here is a more technical and clear explaination:
https://docs.python.org/2/library/copy.html
Except this doesn’t work…
myarray = #(1,2,3,#("a","b","c"))
newArray = deepcopy myarray
newArray[4][3] = "banana"
print myarray[4][3]
--returns "banana"
it illustrates what i say above… it seems like DeepCopy just calls Copy method for every item (value) of Array. because simple Copy of an array value is not a “deep” copy you see the result you have
Actually I got muddled… that works correctly…
It’s when you have an array in a struct that doesn’t work with deepcopy.
I’m always getting headaches with deep copy… these are my most annoying bug finds…
struct s1 (
myValA = #(1,2,3),
myValB = #(#(1,1),#(2,2)),
myValC = 4
)
--instantiate our struct
s = s1()
arrayOfStructs = #(s,s) --two instances of the same struct
--we can test if they are the same....
arrayOfStructs[1] == arrayOfStructs[2] --true
--Problem number 1
--Deepcopy breaks this link....
newArray = deepcopy arrayOfStructs
newArray[1] == newArray[2] --false - INCORRECT
--Problem number 2
--Deepcopy doesn't give a unique pointer to the array in an array
newArray[1].myValA[1] = 5
--Or array of arrays
newArray[1].myValB[1][1] = 2
--but it's fine with non array values.
newArray[1].myValC = 44
--The Deep copy shouldn't have changed the original 's' value.
print s.myValA[1] --5 - INCORRECT
print s.myValB[1][1] --2 - INCORRECT
print s.myValC -- 4 - CORRECT
I have functions to fix the 2 above problems, but maybe we can see if there’s better ways of doing so?
Anything more elegant? This is a bit of a bodge/hack I put together in a hurry for a script once upon a time.
fn trueDeepCopy val =
(
newVal = deepcopy val
if classof val == Array do
(
for o in newVal do
(
if superclassof o == structDef do
(
for p in getpropNames o where (classof (getproperty o p)) == Array do
(
setproperty o p (deepcopy (getproperty o p))
)
)
)
b = #{1..val.count}
for i = 1 to val.count where b[i] do
(
for j = i to val.count where i != j and val[i] == val[j] do
(
b[j] = false
newVal[j] = newVal[i]
)
)
)
newVal
)
An alternative solution from Larry @ Autodesk, which should consider all case scenarios.
fn fixedDeepCopy val mapping: =
(
if mapping == unsupplied do
mapping = datapair #() #()
local newVal
local index = findItem mapping.v1 val
if index != 0 then
newVal = mapping.v2[index]
else if (iskindof val maxwrapper) then
newVal = val
else if classof val == Array then
(
newVal = #()
newVal.count = val.count
for i = 1 to val.count do
(
newVal[i] = fixedDeepCopy val[i] mapping:mapping
)
)
else if (superclassof val) == structDef then
(
newVal = copy val
for p in getpropNames newVal do
(
setproperty newVal p (fixedDeepCopy (getproperty newVal p) mapping:mapping)
)
)
else if (classof val) == DataPair then
(
newVal = copy val
for p in #(#v1, #v2) do
(
setproperty newVal p (fixedDeepCopy (getproperty newVal p) mapping:mapping)
)
)
else
newVal = copy val
if index == 0 do
(
append mapping.v1 val
append mapping.v2 newVal
)
newVal -- return value
)