How to easily copy object instance data?

How to easily copy object instance data?

Working with records have nice feature - when you assign one record to another, Delphi take care about strings and interface reference counting.

But when you have a class it seems the only way to clone object is to make a hand-made assignment of all fields. Are there any easy way to clone instance data without hand-made per-field assignment?

Comments

  1. I don't know any easy way, but maybe look at "finalizerecord"(I think that's the proper name) and implement the same functionality of field by field copy(in stead of freeing) to another instance.

    ReplyDelete
  2. Would it be possible to use (enhanced) RTTI to automate it?

    ReplyDelete
  3. Nicholas Ring Using RTTI is too slow for me.

    ReplyDelete
  4. Alexey Petushkov I think it will depend on how you do your objects. If you have objects within your objects and speed matters, then rolling your own would be required - I think.

    ReplyDelete
  5. Dorin Duminica Nice idea. System._CopyRecord seems to be suitable for this, I'll try!

    ReplyDelete
  6. go for it, maybe share it when you're done on a blog or here?

    ReplyDelete
  7. Currently using RTTI for this, which is slow, but fast enough for us.  We have ORM like functionality which is used for dirty management (ie spotting changed rows), and have a custom RTTI enumeration which uses attributes to select which properties that should be ignored.  With hundreds of row types, it has saved us a lot of duplicate code.

    ReplyDelete
  8. Dorin Duminica Okay, I'll share it on my +page

    ReplyDelete
  9. I have a copy constructor for that case, or Assign method

    ReplyDelete
  10. Simon Stuart So you copied each fields?  Operator is just a syntax sugar for .assign method. I want to use something universal for plain--old-data classes which will clone automatically based on TypeInfo or whatever.  It seems all goodies are hidden in "System" unit, and to extract them it is needed to copy big part of this unit. It can cause license issues  and compatibility with future (or another platform) versions. So i wonder are there any easyiest paths ...

    ReplyDelete
  11. I suggest using Assign because even if you come up with some magic _CopyRecord like implementation (which uses Rtti btw, although very lowlevel one) you are limited to plain data classes (if you have aggregations you start to get into trouble because you need to determine if deep copy or not, who to create aggregation and so on). You will have much more work in the long run finding bugs there than the benefit of not having to maintain the Assign method

    ReplyDelete
  12. Lars Fosdal Well, Im making something like an ORM with context-free models (not bound to DB) as a part of my work project , and easy cloning models is the target. CPU is powerful now, but im not sure what operating with high level RTTI will be fast enought ...

    ReplyDelete
  13. Alexey Petushkov I think you should prototype with new RTTI and low level RTTI and see if the extra effort to handle everything using low level functions is really worth it, we're using high level RTTI in one project and it works OK, it could be faster, but the gain is so little that it doesn't really worth the extra effort, and btw., we only need to copy base types(int, bool, string, double), within about 600 lines of very easy to read code, everything is handled(and there are a lot of comments and empty lines).

    ReplyDelete
  14. I cache some of the RTTI lookup per class to reduce the amount of checking on each compare/clone - it still isn't as fast as I'd like it to be - and some data types (relatively rarely used by us) are not supported by RTTI.

    I'd shave some more time off if there was a class var type which was unique per class declaration, instead of shared for all class descendants. Now, I have to do a lookup per class to find the cache, and that steals a little from the savings.

    ReplyDelete
  15. You can try inheriting from TPersistent. TPersistent allows you to copy the contents of one object to another using the Assign method. Although I'm not sure how they handle non-TPersistant objects. I think for non-TPersistent child objects, these get copied by reference.

    ReplyDelete
  16. Lars Fosdal damn, that's exactly what we do.... when a "new" class is constructed, it gets "parsed" and added to a dictionary, next time you create that class type instance => shazam, you retrieve it's parsed info from the unit "private" dictionary (:

    ReplyDelete
  17. Great minds think alike, Dorin Duminica :)

    ReplyDelete
  18. Lars Fosdal too bad we can't share these things as open source and then benefit from bug fixes and features easily >.<

    ReplyDelete
  19. Dorin Duminica I found nice and easy solution for 2010 up to XE4, please read the test project

    ReplyDelete
  20. saw it, already re-shared it (: will look into it when I get a break...

    ReplyDelete
  21. Dorin Duminica  You was right - some goodies are exported from System unit, so we can use them. Thank you and all topic members for help and ideas.

    ReplyDelete
  22. Have a copy Constructor that takes the old class object as parameter?  then do it manually.  I think C++ used to do that.  But it's still manual...

    ReplyDelete

Post a Comment