Copying an Instance of a Class

How do I duplicate an instance of a class. From what I have read in the Xojo docs I have to create a new class and copy each of the properties across one by one. Painful. I have a class with 40+ properties and need a quick way of duplicating them. Have I read wrong?

Do you really want to clone the instance? Or just have a second reference to it? If it’s a second reference, that’s easy, you just Object1 = Object 2. But if you want to create a standalone instance, yes, you have to copy the properties. I normally create a Copy method that copies each property in turn to the new object.

You could use Introspection.

No copy it. I made the mistake this morning of doing Object1 = Object2 and realised it was a second reference.

Yes I looked at introspection for the first time today. Ive never used it before and had a dabble with exposing property names. One of my properties in my class is an array of RealBasic.Rects, would I need to iterate through these or would simply copying the property from one instance to the other copy the array as is. I ask because if I use intropection I could just the loop through and ClassA.Properties straight to ClassB.Properties

Gavin, do you use introspection in your copy method? If not I might try and knock something up as this would be a very useful and re-useable method which should work on any class and save listing out every property.

Mike, no, I don’t use introspection to copy objects. But it would certainly be a smarter way to do it.

With all the issues of “do I get a second reference to the property in the other object? or do I get a copy of the value?” I would think that handcrafting a copy method would be easier than trying to code all the possibilities using introspection. And more exact. I prefer having control over what exactly happens.

Simple example to illustrate the gotchas

c1 = new class1
c2 = new class2
c1.theDate = new Date
c2.theDate = c1.theDate
c2.theDate.Day = c2.theDate.Day + 1
msgbox c1.theDate.shortdate + "  " + c2.theDate.shortdate

c2 has a reference to, and is manipulating, c1’s date.

The problem is that sometimes having a reference is the desired result. So for every property, you have to ask whether you want a reference or a clone of that object?

You’d need to iterate. Perhaps use Introspection to copy common properties (string, double, etc.), then custom code to copy thing like arrays.

[quote=116465:@Tim Hare]With all the issues of “do I get a second reference to the property in the other object? or do I get a copy of the value?” I would think that handcrafting a copy method would be easier than trying to code all the possibilities using introspection. And more exact. I prefer having control over what exactly happens.

Simple example to illustrate the gotchas

c1 = new class1
c2 = new class2
c1.theDate = new Date
c2.theDate = c1.theDate
c2.theDate.Day = c2.theDate.Day + 1
msgbox c1.theDate.shortdate + "  " + c2.theDate.shortdate

c2 has a reference to, and is manipulating, c1’s date.

The problem is that sometimes having a reference is the desired result. So for every property, you have to ask whether you want a reference or a clone of that object?[/quote]
I see your point Tim but no I want a complete clone. My class is a drawing object, for instance it could be a rectangle or an oval or a text object etc, I am doing copy and paste so I what an exact clone. If I add any properties to the class in the future, I could easily forget to add the property copy in the copy method which is why introspection seems like the best answer. I write the introspection copy method and then whatever changes I make to the class i.e. property names, adding or removing properties, I can be sure the copy always works without changing it.

Pain

You could create your own cloning method from the inside of the class like:

Class Pirate

//Pirate.Ahoy:
Private Function Ahoy() As String
    Return "Ye: "+Str(Dogs)
End Function

Pirate.Scurvy:
Private Sub Scurvy()
    Dogs = (Dogs + 3) / 2
End Sub

Private Dogs As Integer = 1

//Pirate.Clone:
Private Function Clone() As Pirate
    Dim c As NewPirate
    c.Dogs = Dogs
    Return c
End Function

End Class

Dim p1 as New Pirate
p1.scurvy()
Dim p2 as Pirate = p1.clone()

For terminology discussion… There are two types of cloning… Deep and Shallow. Shallow will clone only top level objects while Deep will recurse. You will need to decide for yourself which is more preferable in your instance.

[quote=116470:@Rick Araujo]You could create your own cloning method from the inside of the class like:

[code]
Class Pirate

//Pirate.Ahoy:
Private Function Ahoy() As String
Return "Ye: "+Str(Dogs)
End Function

Pirate.Scurvy:
Private Sub Scurvy()
Dogs = (Dogs + 3) / 2
End Sub

Private Dogs As Integer = 1

//Pirate.Clone:
Private Function Clone() As Pirate
Dim c As NewPirate
c.Dogs = Dogs
Return c
End Function

End Class
[/code][/quote]
Can I just request that we follow Rick’s lead and use “pirate” terminology for all future Xojo code examples? Thanks!

I was merely offering proper terminology for the discussion. You guys are discussion Deep and Shallow methods of cloning. I did not offer a Xojo solution, sorry for the confusion.

For more information on what Deep and Shallow cloning is (copying), see: Object copying - Wikipedia

Jeremy, can you expand on this. Do you mean shallow i.e. only copy the properties which are required to produce a near as damn it clone?

I agree, but i’d love to know how/why pirates were chosen. In the mind of Rick :slight_smile:

[quote=116475:@Jeremy Cowgar]I was merely offering proper terminology for the discussion. You guys are discussion Deep and Shallow methods of cloning. I did not offer a Xojo solution, sorry for the confusion.

For more information on what Deep and Shallow cloning is (copying), see: http://en.wikipedia.org/wiki/Object_copy[/quote]
Ok, I need deep cloning Jeremy. i.e.

Class1.pirate = Class2.pirate

[quote=116477:@Mike Charlesworth]Ok, I need deep cloning Jeremy. i.e.

Class1.pirate = Class2.pirate

Here is a simple CloneInto method. It, however, does a Shallow copy. I offer it here as something to build upon. Bear in mind, a global deep copy method can be very tricky. For example, say you have a Person object that has FirstName As String, LastName As String, Parents() As Person and Children() As Person… You can see how an improperly coded Deep clone could be cloning forever and ever :slight_smile:

Function CloneInto(a As Object, b As Object) As Boolean
  Dim aTi As Introspection.TypeInfo = Introspection.GetType(a)
  Dim bTi As Introspection.TypeInfo = Introspection.GetType(b)
  
  If aTi.FullName <> bTi.FullName Then
    Return False
  End If
  
  For Each p As Introspection.PropertyInfo In aTi.GetProperties
    p.Value(b) = p.Value(a)
  Next
  
  Return True
End Function

I will be doing a Webinar on Introspection at the end of August, it will include a more detailed version of the above method, but above is a place to start, bearing in mind it is a Shallow method.

Oh, a possible change to the above is to not make it return a Boolean, but make it raise an Exception if the types are different.

Religious convictions.