Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2016-02

Assign() vs AssignTo()

10 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Graeme Geldenhuys

Hi,

In TPersistent, we have two virtual methods. Assign() which calls AssignTo().

1) Why are they both virtual? It seems like Assign() is what I call a template method, farming its work out to other helper methods - in this case, AssignTo(). Normally template methods are not virtual, but their helper methods (the ones doing the actual work) are. So again, why is Assign() virtual?

2) Now seeing that both are virtual, and that is probably not going to change in the RTL, which method is the preferred method to override so you have the ability to do MyObject.Assign(MySource)? I've been overriding Assign(), but thinking that maybe I should have overridden AssignTo() instead.

ps:
The FPC (pdf) documentation for TPersistent.Assign() has a "See Also" reference to TPersistent.AssignTo(). But that link doesn't work, because AssignTo is Protected, and the RTL documentation doesn't include Protected methods.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/ My public PGP key: http://tinyurl.com/graeme-pgp
Andreas Schneider
to Graeme Geldenhuys
Graeme Geldenhuys wrote 10 lines
Hi, In TPersistent, we have two virtual methods. Assign() which calls AssignTo(). 1) Why are they both virtual? It seems like Assign() is what I call a template method, farming its work out to other helper methods - in this case, AssignTo(). Normally template methods are not virtual, but their helper methods (the ones doing the actual work) are. So again, why is Assign() virtual?

They are two different directions. AssignTo assigns *from* your current instance onto another, while Assign assigns *from* the other instance into yours.
Sure, by default that should be the same, that's why it's sane to have Assign simply call the other object's AssignTo with Self as target. But IMHO it can't hurt to have the ability to override that behavior for only one direction.

Show quoted text 5 lines
2) Now seeing that both are virtual, and that is probably not going to change in the RTL, which method is the preferred method to override so you have the ability to do MyObject.Assign(MySource)? I've been overriding Assign(), but thinking that maybe I should have overridden AssignTo() instead.

I think that really depends on what direction you want to usually handle. As far as I understand the code, the call in TPersistent is only a fallback, intended like that:
if it is not possible to assign some instance onto another instance (because no class along the hierarchy down to TPersistent implemented an override for Assign that handles the specific case) it tries, if the other side maybe can handle it by calling their AssignTo method.

That way you can allow your class to have some
standard/thirdparty/whatever class assigned, while you certainly can't modify the standard/thirdparty/whatever class to allow assigning *to* your class (since it doesn't even know your class). The same goes for the other way around. If you know a foreign class will try to assign your class, which it doesn't know anything about, it will ultimately come back calling your AssignTo method which will allow your class to handle the assignment onto the foreign class.

Best regards,
Andreas

Martin Schreiber
to Graeme Geldenhuys: In TPersistent, we have two virtual methods. Assign() which calls AssignTo(). 1) Why are…
Graeme Geldenhuys wrote 11 lines
Hi, In TPersistent, we have two virtual methods. Assign() which calls AssignTo(). 1) Why are they both virtual? It seems like Assign() is what I call a template method, farming its work out to other helper methods - in this case, AssignTo(). Normally template methods are not virtual, but their helper methods (the ones doing the actual work) are. So again, why is Assign() virtual?

If one wants to transfer property values from "source" to "dest" one calls "dest.assign(source)". If "dest" does not know how to handle "source" it calls "source.assignto(self)".

Show quoted text 6 lines
2) Now seeing that both are virtual, and that is probably not going to change in the RTL, which method is the preferred method to override so you have the ability to do MyObject.Assign(MySource)? I've been overriding Assign(), but thinking that maybe I should have overridden AssignTo() instead.

It depends on what knows to handle what. Sometimes both have to be overridden.

Martin

Graeme Geldenhuys
to Martin Schreiber
Martin Schreiber wrote
It depends on what knows to handle what. Sometimes both have to be overridden.

Thanks Martin and Andreas. So it's more about which direction you want to go.

Now the other thing that surprised be, I thought TPersistent.Assign() automatically handles protected properties (via RTTI) - thinking that descendants automatically get such functionality for free. But reviewing the RTL code, I see Assign() and AssignTo() really has no functionality implemented by default.

I can only assume that the reason I thought published properties are handled for you (in the RTL), was because 99.9% of my projects are tiOPF based, and it always just worked. Looking now at this in more detail, I see it was indeed tiOPF that always gave me that functionality. Wow, 17+ years later and I only realise that now. :) Never too old to learn. ;-)

Regards,
- Graeme -

Martin Schreiber
to Graeme Geldenhuys
Graeme Geldenhuys wrote 7 lines
Now the other thing that surprised be, I thought TPersistent.Assign() automatically handles protected properties (via RTTI) - thinking that descendants automatically get such functionality for free. But reviewing the RTL code, I see Assign() and AssignTo() really has no functionality implemented by default.

Correct, it depends much on the actual classes what should happen by calling "assign()". So "tpersistent" does nothing by default.

Martin

Dennis
to Martin Schreiber
Martin Schreiber wrote 12 lines
On Thursday 11 February 2016 17:17:32 Graeme Geldenhuys wrote: > Now the other thing that surprised be, I thought TPersistent.Assign() > automatically handles protected properties (via RTTI) - thinking that > descendants automatically get such functionality for free. But reviewing > the RTL code, I see Assign() and AssignTo() really has no functionality > implemented by default. > Correct, it depends much on the actual classes what should happen by calling "assign()". So "tpersistent" does nothing by default. Martin

Is there any sample codes to copy published properties (via RTTI) ? e.g. psuedo code below

   for i := 0 to properties.count -1 do begin
      case properties[i].type of
         vtInteger :  properties[i].AsInteger :=
Source.PropertiesByName(Properties[i].Name).AsInteger;
        vtdouble : ....
        vtString : ...
      end;
   end;
Martin Schreiber
to Dennis
Dennis wrote 13 lines
Is there any sample codes to copy published properties (via RTTI) ? e.g. psuedo code below for i := 0 to properties.count -1 do begin case properties[i].type of vtInteger : properties[i].AsInteger := Source.PropertiesByName(Properties[i].Name).AsInteger; vtdouble : .... vtString : ... end; end;

MSEgui has such code for "trttistat" component, please see https://gitlab.com/mseide-msegui/mseide-msegui/raw/master/lib/common/kernel/mserttistat.pas although it is specialised for saving and editing options.

Martin

Dennis Poon
to Martin Schreiber
Martin Schreiber wrote 20 lines
On Friday 12 February 2016 03:17:57 Dennis wrote: > Is there any sample codes to copy published properties (via RTTI) ? > e.g. psuedo code below > > for i := 0 to properties.count -1 do begin > case properties[i].type of > vtInteger : properties[i].AsInteger := > Source.PropertiesByName(Properties[i].Name).AsInteger; > vtdouble : .... > vtString : ... > end; > end; > MSEgui has such code for "trttistat" component, please see https://gitlab.com/mseide-msegui/mseide-msegui/raw/master/lib/common/kernel/mserttistat.pas although it is specialised for saving and editing options. Martin _______________________________________________

Thank you.

Dennis

Graeme Geldenhuys
to Dennis: Is there any sample codes to copy published properties (via RTTI) ? e.g. psuedo code below
Dennis wrote
Is there any sample codes to copy published properties (via RTTI) ? e.g. psuedo code below

Take a look at tiOPF's TtiObject.AssignPublishedProps() method.

https://sourceforge.net/p/tiopf/code/ci/tiopf2/tree/Core/tiObject.pas#l1156

The tiRTTI.pas unit also has very useful RTTI features - one being access to properties via "property paths". It walks a object hierarchy to get or set a property, and does error checking along the way. eg:

  tiSetProperty(lPerson, 'Address.City.Name', 'London');

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/ My public PGP key: http://tinyurl.com/graeme-pgp
stdreamer
to Graeme Geldenhuys: In TPersistent, we have two virtual methods. Assign() which calls AssignTo(). 1) Why are…
Graeme Geldenhuys wrote 10 lines
Hi, In TPersistent, we have two virtual methods. Assign() which calls AssignTo(). 1) Why are they both virtual? It seems like Assign() is what I call a template method, farming its work out to other helper methods - in this case, AssignTo(). Normally template methods are not virtual, but their helper methods (the ones doing the actual work) are. So again, why is Assign() virtual?

Different functionality you need both of them for different reasons see below.

Show quoted text 5 lines
2) Now seeing that both are virtual, and that is probably not going to change in the RTL, which method is the preferred method to override so you have the ability to do MyObject.Assign(MySource)? I've been overriding Assign(), but thinking that maybe I should have overridden AssignTo() instead.

As a rule of thumb you always override Assign to make sure that your control can copy data from any other. You only override AssignTo to enable 3rd party controls to copy data from your controls.

Lets assume that you right a control TDBGrid based on VirtualstringTree ee TMyDbGrid = class(TVirtualStringTree)
.
.
.
end;
By overriding the assign method you teach TMyDBGrid how to copy data from a TDBGrid. Now lets assume that you want to be able to copy data from your TMyDBGrid to TDBGrid as well you have two choices
1) create a new control
TNewDBGrid = class(TDBGrid)

   end;
  and override the assign method

2) override the AssignTo method of TMyDBgrid control and there copy the data to TDBGrid your self with out touching TDBgrid.

This is a simple but powerful feature that allows you to teach other controls how to copy data from your controls with out the need to change their code. Something common on well written libraries.

PS. The choice of the example control is not random, I came to understand the importance of AssignTo when I coded my own dbgrid and wanted to be able to assign data to multiple other grids including the DevExpress grids.