Recent

Author Topic: Generic copy constructor via restrictions  (Read 908 times)

CG

  • New Member
  • *
  • Posts: 10
Generic copy constructor via restrictions
« on: February 10, 2024, 12:39:50 am »
Recently, I started using generics. I was wondering if it is possible to put a restriction on the type parameter T of a generic such that it is guaranteed within the generic class that the passed class for specialization provides a copy constructor e.g. something like this:
Code: Pascal  [Select][+][-]
  1. T.Create(Source: T);

It could be interesting to create dynamically new instances of T classes in the generic class at runtime. In order to make this work one would need a generic copy constructor as outlined above.

There is just one other idea that came to my mind, but that is rather ugly: One could pass a callback reference to the constructor of the generic class. If in need of the copy constructor one can call the callback from within the class and create a new copy from an allready known instance of T:
Code: Pascal  [Select][+][-]
  1. generic TList<T: TObject> = class(TObject)
  2.   public
  3.     type
  4.       TCopyConstructorCallback = function(const Source: T): T;
  5.     constructor Create(CopyConstructorCallback: TCopyConstructorCallback);
  6.     destructor Destroy();
  7. end;
  8.  
I haven’t tested that idea yet, I am quite sure I can make it work that way but as I said it is really ugly. If there some neat way to avoid it with clever restrictions then I would prefer it.

Any suggestions?

Thanks,
CG

Thaddy

  • Hero Member
  • *****
  • Posts: 15722
  • Censorship about opinions does not belong here.
Re: Generic copy constructor via restrictions
« Reply #1 on: February 10, 2024, 12:59:10 pm »
Any Tobject descendant has a ClassType reference to its own type, so you can create a copy by simply calling Mycopy := MyClass.ClassType.create.
This does not preserve the data, though.
The easiest way to do that is to derive from TPersistent which has standard  possibilities to persist data that can subsequently be read by the copy using the streaming mechanisms provided by Tpersistent.
That works e.g. by making all data access through published properties and the class compiled in {$M+} state. There are other options but that is the easiest one. This is the same mechanism that the IDE uses for storing and loading components but it is not tied to the IDE and can be used everywhere. Object persistance.
This is a deep copy, so after creation, operating on the copy will not affect the original.
You can gather all this and create a function called CopyConstructor... :o ;D
If that is what you mean to achieve I can write a small example.
« Last Edit: February 10, 2024, 01:12:58 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

alpine

  • Hero Member
  • *****
  • Posts: 1263
Re: Generic copy constructor via restrictions
« Reply #2 on: February 10, 2024, 01:11:05 pm »
TPersistent.Assign/AssignTo?

@CG
And why the need of copy constructor since in ObjectPascal the class instances where not meant to be created implicitly?
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

CG

  • New Member
  • *
  • Posts: 10
Re: Generic copy constructor via restrictions
« Reply #3 on: February 11, 2024, 12:05:37 am »
@Thaddy A brief example for using TPersistent would be great. Would I be using TPersistent instead of TObject for the restriction and then make use of TPersistent.Assign()? Looking forward to a brief example.

In my private projects I did the serialization of objects on my own to reduce dependencies. I am not that fluent with the build-in support that free pascal has to offer. In particular I don’t understand well the limitations that would come with using TPersistent.
 
To make use of TPersistent in the generic the class used for specializing the generic needs to be an ancestor of TPersistent.
  • Are there any further limitations?
  • Do I have to use/implement the observer stuff mentioned in TPersistent?
  • TPersistent.GetNamePath is declared virtual so I assume I have to provide some code here in my TPersistant-derived class that I want to use for the specialization of the generic.
  • You mentioned the compiler switch {$M+}. I haven't used the switches so far. Do the switches work on single *.pas files or would they affect the whole project?
 
I guess a minimalistic skeleton example would be great. I can then experiment on my own from there.

TRon

  • Hero Member
  • *****
  • Posts: 3283
Re: Generic copy constructor via restrictions
« Reply #4 on: February 11, 2024, 12:19:31 am »
  • You mentioned the compiler switch {$M+}. I haven't used the switches so far. Do the switches work on single *.pas files or would they affect the whole project?
Although not being Thaddy I can answer that one quickly for you: it depends. See manual and note the distinction between local and global directives.
This tagline is powered by AI

jamie

  • Hero Member
  • *****
  • Posts: 6580
Re: Generic copy constructor via restrictions
« Reply #5 on: February 11, 2024, 02:21:23 am »
Don't know what you are really up to but, you can have an Array of TCollection for which you can store or create numerous objects of each type.

 The whole thing would look like a tree memory, but each object record needs to be descendant from a TCollectionItem.
etc.

The only true wisdom is knowing you know nothing

Thaddy

  • Hero Member
  • *****
  • Posts: 15722
  • Censorship about opinions does not belong here.
Re: Generic copy constructor via restrictions
« Reply #6 on: February 11, 2024, 10:58:41 am »
Actually, Alpine's answer covers my own answer if you look how TPersistent.Assign() is implemented.
If I smell bad code it usually is bad code and that includes my own code.

 

TinyPortal © 2005-2018