Re: [fpc-devel] restbase.pp LoadFromJSON calling StopRecordPropertyChanges;
I see a couple of problems TBaseObject.SaveToJSON 1) TBaseObject.SaveToJSON cannot distinguish properties that are part of the REST protocol from properties that are not part of it. It only knows that properties which have been modified are part of the rest protocol, but properties which have not been modified might be part of the REST protocol or might not be. For example, a client receives a JSON object from a server (via LoadFromJSON) and wants to persist the complete JSON object to disk, database, or send it to another server. But, at present, there is no way to save all the properties that are part of the REST protocol without getting contaminated with non-REST properties. 2) Lack of control. With TBaseObject.SaveToJSON it would be nice to control what is saved (Save all REST properties, or Save modified REST properties). ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] restbase.pp LoadFromJSON calling StopRecordPropertyChanges;
Michael wrote: > >> Because there may be other published properties that are not part of the > >> REST protocol. You may for instance decide to add published properties to a > >> base class that describe where to save the object in a local database. Wayne wrote: > > Ok, that clears up that. If I understand correctly, the behavior > > should be as follows: > > > > (restbase.pp) > > In TBaseObject descendants, SaveToJSON only saves object properties > > defined directly in the final descendant class and none of the > > properties of parent classes. This is implemented by only marking > > properties as modified that are defined directly in the final > > descendant class and skipping properties of all parent classes (which > > always appear to be unmodified, and thus not saved). This prevents > > properties which are not part of the REST protocol from contaminating > > the generated JSON. It follows that REST protocol properties should > > always be defined in the final TBaseObject descendant class (and not > > in any base or intermediate classes). Michael wrote: > While in practice most REST classes will be the final classes, > it should be possible to support inheritance in rest classes, > that is why the 'ParentPropertyCount' exists and is taken into account. My summary above is incorrect. How about this?: In TBaseObject descendants, SaveToJSON only saves object properties which have had their properties marked as modified using MarkPropertyChanged (modified flags are stored internally using TBits). Properties which have not been marked as modified will not be saved to JSON. This prevents properties which are not part of the REST protocol from contaminating the generated JSON. Auto generated code that defines TBaseObject descendant classes declares properties with index specifiers and setter methods that call MarkPropertyChanged. When a property is changed in these auto generated classes, that property will end up in the output of SaveToJSON. Properties which are a valid part of the REST protocol, but which have not been changed are not included in the generated JSON. Properties can be defined in a TBaseObject final descendant class or parent classes and be included in the JSON output (as long as MarkPropertyChanged has been called with the corresponding index for that property). ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] restbase.pp LoadFromJSON calling StopRecordPropertyChanges;
On Sat, 14 Jan 2023, Wayne Sherman wrote: On Sat, Jan 14, 2023 at 12:36 PM Michael Van Canneyt wrote: On Sat, 14 Jan 2023, Wayne Sherman wrote: On Sat, Jan 14, 2023 at 10:34 AM Michael Van Canneyt wrote: On Sat, 14 Jan 2023, Wayne Sherman wrote: 2) Doesn't each object already have the parent properties included in its own properties by inheritance? Why this question ? An object does not know the property count of the parent. True, but why does it need to know the property count of the parent? TBaseClass = class private FField1: integer; protected FPropModifiedFlags: TBits; published property Field1: integer read FField1 write FField1; end; GetTypeData(TBaseClass.ClassInfo)^.PropCount = 1 TDescendant = class(TBaseClass) private FField2: integer; published property Field2: integer read FField2 write FField2; end; GetTypeData(TDescendant.ClassInfo)^.PropCount = 2 TDescendant has two properties (one inherited and one declared directly) and let's say it can record if any of the properties have been modified. So why does it have to know about the number of properties it inherited vs the properties it declares directly? Because there may be other published properties that are not part of the REST protocol. You may for instance decide to add published properties to a base class that describe where to save the object in a local database. Ok, that clears up that. If I understand correctly, the behavior should be as follows: (restbase.pp) In TBaseObject descendants, SaveToJSON only saves object properties defined directly in the final descendant class and none of the properties of parent classes. This is implemented by only marking properties as modified that are defined directly in the final descendant class and skipping properties of all parent classes (which always appear to be unmodified, and thus not saved). This prevents properties which are not part of the REST protocol from contaminating the generated JSON. It follows that REST protocol properties should always be defined in the final TBaseObject descendant class (and not in any base or intermediate classes). While in practice most REST classes will be the final classes, it should be possible to support inheritance in rest classes, that is why the 'ParentPropertyCount' exists and is taken into account. Michael. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] restbase.pp LoadFromJSON calling StopRecordPropertyChanges;
On Sat, Jan 14, 2023 at 12:36 PM Michael Van Canneyt wrote: > On Sat, 14 Jan 2023, Wayne Sherman wrote: > > On Sat, Jan 14, 2023 at 10:34 AM Michael Van Canneyt wrote: > >> On Sat, 14 Jan 2023, Wayne Sherman wrote: > >>> 2) Doesn't each object already have the parent properties included in > >>> its own properties by inheritance? > >> > >> Why this question ? > >> An object does not know the property count of the parent. > > > > True, but why does it need to know the property count of the parent? > > > > TBaseClass = class > > private > >FField1: integer; > > protected > >FPropModifiedFlags: TBits; > > published > >property Field1: integer read FField1 write FField1; > > end; > > > > GetTypeData(TBaseClass.ClassInfo)^.PropCount = 1 > > > > TDescendant = class(TBaseClass) > > private > >FField2: integer; > > published > >property Field2: integer read FField2 write FField2; > > end; > > > > GetTypeData(TDescendant.ClassInfo)^.PropCount = 2 > > > > TDescendant has two properties (one inherited and one declared > > directly) and let's say it can record if any of the properties have > > been modified. So why does it have to know about the number of > > properties it inherited vs the properties it declares directly? > > Because there may be other published properties that are not part of the > REST protocol. You may for instance decide to add published properties to a > base class that describe where to save the object in a local database. Ok, that clears up that. If I understand correctly, the behavior should be as follows: (restbase.pp) In TBaseObject descendants, SaveToJSON only saves object properties defined directly in the final descendant class and none of the properties of parent classes. This is implemented by only marking properties as modified that are defined directly in the final descendant class and skipping properties of all parent classes (which always appear to be unmodified, and thus not saved). This prevents properties which are not part of the REST protocol from contaminating the generated JSON. It follows that REST protocol properties should always be defined in the final TBaseObject descendant class (and not in any base or intermediate classes). ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] restbase.pp LoadFromJSON calling StopRecordPropertyChanges;
On Sat, Jan 14, 2023 at 10:34 AM Michael Van Canneyt wrote: > On Sat, 14 Jan 2023, Wayne Sherman wrote: > > 3) Why does MarkPropertyChanged offset the index and > > IsPropertyModified does not take the offset into account? > > They should be the same. I don't remember why I created the two methods > differently. For property index specifiers, it seems that NameIndex might be the wrong index used in IsPropertyModified: function TBaseObject.IsPropertyModified(Info: PPropInfo): Boolean; begin Result:=Not Assigned(FBits) or FBits.Bits[Info^.NameIndex] end; and possibly the rtl docs are incorrect(?): https://www.freepascal.org/docs-html/rtl/typinfo/tpropinfo.html Index - Index for array properties NameIndex - Index for indexed properties << IS THIS CORRECT? In the typinfo.pp unit, a comment indicates that NameIndex has to do with property names (i.e. not the index specifier) https://gitlab.com/freepascal.org/fpc/source/-/blob/main/rtl/objpas/typinfo.pp#L1689 // Don't overwrite properties with the same name if PropList^[TP^.NameIndex]=nil then PropList^[TP^.NameIndex]:=TP; // Point to TP next propinfo record. // Located at Name[Length(Name)+1] ! TP:=aligntoptr(PPropInfo(pointer(@TP^.Name)+PByte(@TP^.Name)^+1)); Dec(Count); end; NameIndex in Delphi typeinfo also has to do with Names of properties and Index has the information on indexed properties: https://docwiki.embarcadero.com/Libraries/Sydney/en/System.TypInfo.TPropInfo Index - The index of the property. It is used as a parameter to the GetProc and SetProc methods on indexed properties. NameIndex - The offset into the Name field where the property's name starts. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] restbase.pp LoadFromJSON calling StopRecordPropertyChanges;
On Sat, 14 Jan 2023, Wayne Sherman wrote: On Sat, Jan 14, 2023 at 10:34 AM Michael Van Canneyt wrote: On Sat, 14 Jan 2023, Wayne Sherman wrote: 2) Doesn't each object already have the parent properties included in its own properties by inheritance? Why this question ? An object does not know the property count of the parent. True, but why does it need to know the property count of the parent? TBaseClass = class private FField1: integer; protected FPropModifiedFlags: TBits; published property Field1: integer read FField1 write FField1; end; GetTypeData(TBaseClass.ClassInfo)^.PropCount = 1 TDescendant = class(TBaseClass) private FField2: integer; published property Field2: integer read FField2 write FField2; end; GetTypeData(TDescendant.ClassInfo)^.PropCount = 2 TDescendant has two properties (one inherited and one declared directly) and let's say it can record if any of the properties have been modified. So why does it have to know about the number of properties it inherited vs the properties it declares directly? Because there may be other published properties that are not part of the REST protocol. You may for instance decide to add published properties to a base class that describe where to save the object in a local database. Michael. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] restbase.pp LoadFromJSON calling StopRecordPropertyChanges;
On Sat, Jan 14, 2023 at 10:34 AM Michael Van Canneyt wrote: > On Sat, 14 Jan 2023, Wayne Sherman wrote: > > 2) Doesn't each object already have the parent properties included in > > its own properties by inheritance? > > Why this question ? > An object does not know the property count of the parent. True, but why does it need to know the property count of the parent? TBaseClass = class private FField1: integer; protected FPropModifiedFlags: TBits; published property Field1: integer read FField1 write FField1; end; GetTypeData(TBaseClass.ClassInfo)^.PropCount = 1 TDescendant = class(TBaseClass) private FField2: integer; published property Field2: integer read FField2 write FField2; end; GetTypeData(TDescendant.ClassInfo)^.PropCount = 2 TDescendant has two properties (one inherited and one declared directly) and let's say it can record if any of the properties have been modified. So why does it have to know about the number of properties it inherited vs the properties it declares directly? ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] restbase.pp LoadFromJSON calling StopRecordPropertyChanges;
On Sat, 14 Jan 2023, Wayne Sherman wrote: On Fri, Jan 13, 2023 at 11:48 PM Michael Van Canneyt wrote: Markpropertychanged is called in the setter of the properties generated by the code generator: Check all generated units. Thanks for your explanations, it is getting more clear how modified property tracking is being used. More clarification please. MarkPropertyChanged offsets the property changed index (to TBits) by the ClassParent total property count, but IsPropertyModified does not take this offset into account. Consider this example: TBaseObject --> TGoogleBaseObject --> TSchema --> TMySchema TBaseObjectClass = Class of TBaseObject; If the object is TMySchema, in GetParentPropCount the TBits index gets offset by (see reference code below): TBaseObjectClass(TSchema).GetTotalPropCount; If the object is TSchema, the TBits index gets offset by: TBaseObjectClass(TGoogleBaseObject).GetTotalPropCount; Questions: 1) Since the ClassParent is always cast as TBaseObjectClass isn't this the same as just TBaseObjectClass(Self.ClassType)? No. The method is virtual, so the actual descendant's method is called. 2) Doesn't each object already have the parent properties included in its own properties by inheritance? Why this question ? An object does not know the property count of the parent. 3) Why does MarkPropertyChanged offset the index and IsPropertyModified does not take the offset into account? They should be the same. I don't remember why I created the two methods differently. Michael. Reference for above questions: class function TBaseObject.GetParentPropCount: Integer; begin if (ClassParent=TBaseObject) or (ClassParent=Nil) then Result:=0 else Result:=TBaseObjectClass(ClassParent).GetTotalPropCount; end; procedure TBaseObject.MarkPropertyChanged(AIndex: Integer); begin If Assigned(FBits) then FBits.SetOn(GetParentPropCount+(AIndex shr IndexShift)); end; function TBaseObject.IsPropertyModified(Info: PPropInfo): Boolean; begin Result:=Not Assigned(FBits) or FBits.Bits[Info^.NameIndex] end; ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] restbase.pp LoadFromJSON calling StopRecordPropertyChanges;
On Fri, Jan 13, 2023 at 11:48 PM Michael Van Canneyt wrote: > Markpropertychanged is called in the setter of the properties generated by > the code generator: Check all generated units. Thanks for your explanations, it is getting more clear how modified property tracking is being used. More clarification please. MarkPropertyChanged offsets the property changed index (to TBits) by the ClassParent total property count, but IsPropertyModified does not take this offset into account. Consider this example: TBaseObject --> TGoogleBaseObject --> TSchema --> TMySchema TBaseObjectClass = Class of TBaseObject; If the object is TMySchema, in GetParentPropCount the TBits index gets offset by (see reference code below): TBaseObjectClass(TSchema).GetTotalPropCount; If the object is TSchema, the TBits index gets offset by: TBaseObjectClass(TGoogleBaseObject).GetTotalPropCount; Questions: 1) Since the ClassParent is always cast as TBaseObjectClass isn't this the same as just TBaseObjectClass(Self.ClassType)? 2) Doesn't each object already have the parent properties included in its own properties by inheritance? 3) Why does MarkPropertyChanged offset the index and IsPropertyModified does not take the offset into account? Reference for above questions: class function TBaseObject.GetParentPropCount: Integer; begin if (ClassParent=TBaseObject) or (ClassParent=Nil) then Result:=0 else Result:=TBaseObjectClass(ClassParent).GetTotalPropCount; end; procedure TBaseObject.MarkPropertyChanged(AIndex: Integer); begin If Assigned(FBits) then FBits.SetOn(GetParentPropCount+(AIndex shr IndexShift)); end; function TBaseObject.IsPropertyModified(Info: PPropInfo): Boolean; begin Result:=Not Assigned(FBits) or FBits.Bits[Info^.NameIndex] end; ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Why: "Can't take the address of constant expressions" here?
On 1/13/23 5:35 AM, Bart via fpc-devel wrote: On Fri, Jan 13, 2023 at 11:13 AM wkitty42--- via fpc-devel wrote: First of all, adding a 'end;" for the "with" compiles under Linux. That's because widestring=unicodestring on Linux. i'm a little surprised there is no "mismatched begin/end" error with the caret pointing to the 2nd begin... -- That's a copy/paste error.by me. The original code had about 10 more function calls and then a closing end for the "with WideStringManager do begin " oh! that would explain it :lol: -- NOTE: No off-list assistance is given without prior approval. *Please keep mailing list traffic on the list where it belongs!* ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel