Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Cloned object modifying original instantiation


  • Please log in to reply
3 replies to this topic
tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007

Hi

 

I tested creating these 2 objects. TriangleArr object has an array of Triangle objects as one of its properties.

Inside the TestDraw method we are attempting to create a copy of each Triangle object in the array in order to make modifications, whilst leaving the original object intact. Why does it seem to modify the original object no matter what I try (Cloning - Which is a shallow copy, or even instantiating a new Traingle object with the parameters of the original)?

 

a1.triangles[1].points[1] should always display 0 in this example, and not increment each time TestDraw is called.

 

Thanks

a1 := new TriangleArr([new Triangle([0,100,50,0,100,100])], {x:0,y:0})
MsgBox, % a1.triangles[1].points[1]    ;%
a1.position.x += 25
a1.TestDraw()
MsgBox, % a1.triangles[1].points[1]    ;%
return

class TriangleArr
{
    triangles := []
    position := {}
    
    __New(triangles, position)
    {
        this.triangles := triangles
        this.position := position
    }
    
    TestDraw()
    {
        loop % this.triangles._MaxIndex()    ;%
        {
            ; Both of the following modify the original object
            s := this.triangles[A_Index].Clone()
            ;s := new Triangle(this.triangles[A_Index].points)
            
            loop % s.points._MaxIndex()    ;%
            {
                s.points[A_Index] += Mod(A_Index, 2) ? this.position.x : this.position.y
            }
        }
    }
}

class Triangle
{
    points := []
    
    __New(points)
    {
        this.points := points
    }
}


trismarck
  • Members
  • 390 posts
  • Last active: Nov 25 2015 12:35 PM
  • Joined: 02 Dec 2010

Shallow copy works like this:

  • create a new object
  • create all keys the old object had in the new object
  • if the value of key in old object was a non-object, copy the value to new object
  • if the value of key in old object was an object (a reference to an object), put a reference to that object into key of new object

Thus after the shallow copy operation, keys of the new object that contained a value that was a reference to an object, hold references to objects in the old object.

s := this.triangles[A_Index].Clone()

Key "points" in s.points and this.triangles[A_Index].points contains a reference to the same underlying object.

s := new Triangle(this.triangles[A_Index].points)

The reference to the object this.triangles[A_Index].points is passed to Triangle.__New(), where this.points stores another _reference_ to that object.

 

To copy all objects recursively, a deep clone function has to be used.

 

HTH.


Edited by trismarck, 19 March 2014 - 09:49 PM.

New Autohotkey forum: http://ahkscript.org.


uname
  • Members
  • 194 posts
  • Last active: Oct 17 2015 08:46 AM
  • Joined: 13 Jun 2012
ObjFullyClone(obj) {
    nobj := ObjClone(obj)
    for k,v in nobj
        if IsObject(v)
            nobj[k] := ObjFullyClone(v)
    return nobj
}
source

tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007

Thank you for the information and that useful recursive function. I had decided to just create a new instance of my object and clone the one property that was an array to pass as a parameter when instantiating it. I will definitely keep the ObjFullyClone function though for future as it is more robust and can be used for more complex classes.