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
[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
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.