Menu Content/Inhalt
Start arrow HS Object Kernel arrow HS OK - Articles arrow Basics of the construction and functionality of HSOK
Basics of the construction and functionality of HSOK: THSObject class Print
20 June 2007
Article Index
THSField class
THSBaseObject class
THSObject class
THSBaseList and descendants
"Weak" and "strong" references
Unicode support
XML support
The kernel object

THSObject class

THSObject class, inherting from THSBaseObject introduces mechanisms of object fields management and memory used by them. Fields supported by HSOK are implemented as a list of references to objects representing them. Only fields that actually have values are kept in memory. These fields as well as the list of references to them are allocated automatically with the first write access to a field. This means that in HSOK an empty object does not utilize memory, on the contrary to e.g. records or classic objects that always allocate memory for all its fields.

THSObject class also implements HasValue property declared in THSBaseObject, addressing the problem of NULL values in object fields. To do this it uses an array FHasValue of THSByteArray type, which stores information about fields having value. Each field is represented by one bit. The array is reallocated dynamically when needed, with succesive write access to fields. It saves memory, especially when out of a few tens of fields we use only first several. That is why it is better to declare the most frequently used fields at the beginning of an object.

THSObject class defines read/write methods  for primitive types, supported by THSStringField, THSByteField, THSSmallIntField classes etc. The field itself is defined in the section "published" of a class as an array property with a declared index, which corresponds to the position of the field in the fields list of the class, e.g.:

property  Name : string index idxName read GetHSStringField write SetHSStringField;

where idxName is a constant declared in the section "const" of the class module. The set method SetHSStringField creates the field if it does not exist and then sets its value. The get method GetHSStringField returns value of the field or default value (in this case an empty string) when the field does not exist (actually has a NULL value). All other fields are supported in the same way. This mechanism saves memory and simplifies the coding process because the whole memory management is done in the "background". For example we can write:

Car.Engine.Gearbox.Pulley.Diameter := 23;

and be sure that if subobjects Engine, Gearbox, Pulley and the field Diameter did not exist they just have been created (note that this is the case of setting a value). We can acces fields also by the Fields property, which allows us e.g. to iterate objects representing fields in a loop. Methods FieldClassByIndex, FieldSizeByIndex, FieldNameByIndex, FieldIndexByName are Delphi's RTTI mechanisms correspondents. They are overridden in descedants and their content is generated and optimized automatically by the Class Editor. Thanks to optimization (e.g. binary search in FieldIndexByName) they work faster than corresponding Delphi's RTTI mechanisms. Finding a field of a given name quickly is essential for fast reading of text and XML files (see HSOK vs InstantObjects™). Along with LastUsedField, FieldIndexByRef, FieldByName these methods simplify creation of generalized algorithms operating on objects of different classes - e.g. methods for saving any object in a relational database or generating an edit form when requested.

Object data proccessing is simplified by methods :

  1. ClearFields – clears all fields
  2. ClearFieldsExcept – clears all fields except given ones
  3. CopyFields – copies given fields from an object
  4. CopyDataExcept – copies all fields except given ones
  5. ByMask – returns field value as text, according to given mask
  6. HasFeatures – returns TRUE, if chosen fields have given values
  7. CompareFeatures – compares chosen fields with given values and returns -1 (values are lower than given), 0 (equal) or 1 (higher)

Arguments of ClearFields, ClearFieldsExcept, CopyFields etc. methods can be numbers, field names or even paths to them which allows us to write:

DataSADUE.ClearFields(['SADPosition[?].NCTSData.P17DestinationCountry']);

which means "clear the field P17DestinationCountry of the field NCTSData in all elements of the SADPosition list". The same could be done by :

with DataSADUE do 
 if HasValue [isaeSADPosition]
  then with SADPosition do
   for i := 0 to PosCount-1 do
    with Position [i] do
      if HasValue [ipozNCTSData]
        then NCTSData.HasValue [idncP17DestinationCountry] := false; 

The first example is pretty short and obvious. It works much slower though, because the path to the field must be analyzed in runtime. We recommend it in application proptotyping or in cases, where efficiency isn't essential.