ABSTRACT CLASS Persistent

Framework for child class serialization, storage and versioning


Sub classes

Configuration

Return

The function Persistent() returns the class object of the Persistent class.

Description

Each instance of a child of the Persistent class contains a member :version that is used to indicate the currentness of the (possibly persistent) instance. The methods :uptoDate(), :verUpdate() and :antiquated() utilize the :version instance data member for comparison with the class :C_version data member

The Persistent-child instance member :savedCfg is always initialized as false; by definition, at time of creation an instance has not been read from persistent storage. The only action that can change the value of :savedCfg is reading back a serialized instance with the :fromDisk() method. The :toDisk() does not modify the value of :savedCfg (however, an instance serialized by :toDisk() will not normally become a runtime instance except when instantiated with :fromDisk()).

The Persistent class supports the framework for introspection via the standard data members :_data and :_methods. However, since Persistent cannot itself be instantiated, it cannot expose instance introspection.

Class Data

:C_data [EXPORTED; Array (member data list)]
Introspection data for curent child class of Persistent class in the library. This data might differ from the introspection data of a persistent (serialized) Persistent instance.
:C_methods [EXPORTED; Array (member methods list)]
Introspection data for curent child class of Persistent class in the library. This data might differ from the introspection data of a persistent (serialized) Persistent instance.
:C_version [EXPORTED READONLY; Numeric (version number)]
Version number of current child class of Persistent class in the library This version number might differ from the introspection data of a persistent (serialized) Persistent instance.

Class Methods

:exposeSelf() [DEFERRED]
When implemented in a child class, :exposeSelf() is responsible for setting the child class' introspection and version data. All of the exposable data and method members of the child should be listed in :C_data and :C_methods, respectively. However, the exposed members declared in Class Persistent itself, will be added to the introspection data by :exposeParent().
:exposeParent()
Add the exposable members of Persistent to child class' introspection data members :C_data and :C_methods. At present, only the data members :version and :savedCfg are exposed; only the DEFERRED Class Persistent methods are exposed, since all of those implemented within Persistent are shallowly called by the child in its own method implementations.

Trying to declare the method :initClass() as DEFERRED runs into some problems in Xbase++ viz our introspection implementation. Therefore, :initClass() is simply not declared in Persistent. Nonetheless, :initClass() should effectively be considered a DEFERRED method, and a child is responsible for defining an :initClass(). In most cases, this declaration can consist of exactly the following:

INLINE CLASS METHOD initClass
  ::exposeSelf()
  ::exposeParent()
RETURN self

Life Cycle

Since Persistent is an abstact class, remarks about the specific implementation life cycle of a child class are subject to override. However, in a "normal" case, the life cycle of a child class will be as described.

An instance of a child class of Persistent normally comes into existence immediately upon its assignment with the ChildClass():new() method. No seperate :create() method is required to request system resources.

A Persistent-child instance is destroyed when its variable falls out of its declaration scope. In principle, the variable containing a Persistent instance can be declared LOCAL to a function, and the exit condition of the controlling function will preform all necessary destruction of the instance.

Instance Data

:_data [EXPORTED; Array (member data list)]
Introspection data to expose member data.
:_methods [EXPORTED; Array (member methods list)]
Introspection data to expose member methods.
:savedCfg [EXPORTED; Boolean (.F.)]
Was this instance read from a diskfile?
:version [EXPORTED; Numeric (Persistent():C_version)]
Version number of this instance (used for comparison with Class data :C_version in determining whether a serialized instance contains out-of-date Persistent fields. Version number encodes the date of last change to the Class definition, i.e. 19990923.

Instance Methods

Instance methods of Persistent behave in a somewhat unusual manner because Persistent is an abstract class, and because of our standard for implementation of introspection.

The action performed by each Persistent instance method is performed not upon "self", as is done in instance methods of most classes, but upon a passed in special parameter "child". The "child" parameter is always the "self" object of the child class instance. Persistent methods come in pairs, one with an initial underscore, its match beginning with a letter, and declared as DEFERRED. In the simplest case, a child class will implement one of these DEFERRED methods in the following manner:

INLINE METHOD foo([...]) ; RETURN ::Persistent:_foo(self, [...])

The implementation of the method named with an initial underscore will resemble:

METHOD Persistent:_foo(child, [...])
  [...]
  BarFunc(child)
  [...]
RETURN child

Notice that if an instance object is returned, this object will normally be the object "child" rather than the object "self".

:init() [DEFERRED]
:_init(<child>)
Set introspection data members and default values for exposed data members (see child Class method :new() for a discussion of the special initializiation procedure of this class)

The :_init() method of the Persistent class, and thereby (normally) indirectly the :new() method of child classes, initializes introspection data in a somewhat unusual manner, compared to other classes. Since Persistent-child instances are designed to be serialized and persistently stored, it is necessary to store introspection data in Class data members, as well as in the instance itself. Doing this allows comparison of a serialized instance with current Class data. Therefore, ::_data and ::_methods are initialized as Persistent():C_data and Persistent():C_methods, respectively. Also ::version is initialized with its corresponding Class data, Persistent():C_version.

:toDisk() [DEFERRED]
:_toDisk(<child>, <cFile>)
Writes a serialized copy of the instance to a diskfile. Parameter <cFile> is required by :_toDisk(), but the child class may choose to implement a default value.
:fromDisk() [DEFERRED]
:_fromDisk(<child>, <cFile>)
Reads a serialized copy of a Persistent instance from diskfile. (if possible). If no file is specified, or if the file specified does not exist, ::savedCfg is simply set to .F., and a reference to the original instance is returned. Otherwise, the serialized data is read in, ::savedCfg is set to .T., and the read instance is returned.

Since XBase++ does not allow redefinition of self, the methods :fromDisk() and :verUpdate() return the modified Persistent-child instance, but do not update the existing instance in-place.

:antiquated() [DEFERRED]
:_antiquated(<child>)
Return a character string report of the differences (if any) between the calling instance's and the Class' introspection data and version number.
:verUpdate() [DEFERRED]
:_verUpdate(<child>)
Returns an updated copy of an instance. Any data members of the current Class' instrospection data that are also present in the instance are copied into a new instance of the Persistent-child class. All other data members, and all methods, are defined according to the definition and initialization values of the most current version.

Since XBase++ does not allow redefinition of self, the methods :fromDisk() and :verUpdate() return the modified Persistent-child instance, but do not update the existing instance in-place.

:uptoDate() [DEFERRED]
:_uptoDate(<child>)
Returns a boolean value indicating whether the calling instance is current with the Class definition in the Library.

Examples

Files

Source file is Persistent.prg


See Also: