Framework for child class serialization, storage and versioning
The function Persistent() returns the class object of the Persistent class.
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.
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
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 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".
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.
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.
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.
Source file is Persistent.prg