Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

delphi prototype pattern

I was wondering, is there anything in the RTTI of Delphi that will do the same as MemberwiseClone does in C# for the simple implementation of the prototype pattern. I saw some Delphi implementations of this pattern where a new object is being created (TMyObject.Create) and it's properties assigned with values from the prototyping object. I might be wrong, but I don't see the benefit of the pattern if we the objects are created in that same basic manner.

Thank you.

like image 423
elector Avatar asked Nov 30 '22 17:11

elector


2 Answers

Object.MemberwiseClone Method makes a shallow copy of the object following some very simple rules and taking advantage of how the .NET garbage collector works.

  • References are simply copied. This includes strings and references to any object.
  • Value types are bit-copied (identical clones are made).

The part about the value types can easily be duplicated with Delphi. Duplicating the reference-type behavior with Delphi, while technically easy, will not provide the expected result: Delphi code is expected to .free the objects it creates, and it uses a owner-owned paradigm to make sure that happens. The usual pattern is to free objects created by the owner-object from the destructor. If you make a shalow-copy of the object, this results in failure. Here's an example:

  • Object A owns a reference to object B.
  • We create object C as a shallow copy of object A. Object C now contains a reference to object B.
  • We free object A: A.Free;
  • We free object B: B.Free; - this automatically calls B.Free, but unfortunately B was already freed when we freed A!

We could attempt a deep-copy, as David suggests, but that poses some equally difficult problems:

  • Not all objects should be copied, for example because they encapsulate references to real-world resources (example: TFileStream).
  • Some other objects can't be deep-copied because they're in essance Singletons. And there's no universal way of saying "This object is a Singleton, do a plain reference copy, don't do a deep copy". Example: Do we copy Application?
  • If you do a deep copy you might have circular-references, you need to take care of those. That's not trivial, and you start the copy from an item in a collection, you might find yourself back to the parent of your collection, ie: not exactly the expected result.
  • Indiscriminate deep-coping might take up unexpected amounts of memory and result in unexpected memory leaks. Think about the collection -> item -> copy item example again, where you end up with a copy of the "item", but the whole COLLECTION was copied because of unexpected back-links.

Putting this all together we can only reach one conclusion: We can't have a general purpose, Delphi equivalent of MemberwiseClone. We can have a partial look-alike for simpler objects with uncomplicated interactions, but that's not nearly as appealing!

like image 81
Cosmin Prund Avatar answered Dec 06 '22 00:12

Cosmin Prund


There's nothing built in that will perform a deep-clone for you. I'm sure you could write a deep-clone based on the new RTTI, but I'd expect it to be a non-trivial amount of work.

If you were dealing with simple enough types it would work fine, but you could easily run into serious challenges. For example, off the top of my head:

  • Some groups of objects need to be created in a specific order.
  • Some members of a class should not be cloned, e.g. reference counts. How do you recognise those with RTTI?
  • How do you deal with singletons?
  • What about any extrinsic references that need to be set up? Suppose you clone an object that is normally created by a factory. If that factory holds a reference to the objects it creates then going behind its back may break your design.

You could implement your prototype pattern by defining a basic Clone() method which uses RTTI for simple types and then you have to override it for anything more complex. Personally though, I'd inherit from TPersistent and make my Clone() method based on Assign.

like image 36
David Heffernan Avatar answered Dec 06 '22 02:12

David Heffernan