Pre and Postoperations for setters

Setting member variables can require additional checks. Some of these checks can be modelled through the static type system (a temperature below -273.15C is most likely to be a data problem) others cannot (for instance the amount a customer may withdraw from his bank account will depend on the rating of that customer - even if the temparature is above -273.15C). 
To support the enforcement of pre and post-conditions the user may configure pre and post operations for member setters (which default to no-ops):

pre operations

template<class ReflectedClass, class AttributeTag, class ValueType> 
void preSet(ReflectedClass& rec, AttributeTag tag, ValueType val)
{ /* whatever needs to be done */}
		

the same for static member variables:

template<class ReflectedClass, class AttributeTag, class ValueType> 
void preSet(AttributeTag tag, ValueType val)
{ /* whatever needs to be done */}
		

post operations

template<class ReflectedClass, class AttributeTag> void
postSet(ReflectedClass& rec, AttributeTag)
{ /* whatever needs to be done */}
		
template<class ReflectedClass, class AttributeTag> void
postSet(AttributeTag)
{ /* whatever needs to be done */}
		

Note that the generative algorithms defined in the library operate on references to member variables and hence pre and post operations are not applied when member variables are changed through a generative algorithm. One application of generative algorithms is to read / write reflected state from / to persistent storage (database, file). Usually it is assumed that when dumping an object, this object's state is consistent. As a consequence deserialization can assume that no invariants were violated and hence no checks are needed before the state of a member variable is restored. This may improve the performance (and it definitely makes the implementation of the generative algorithms easier).

Nonetheless flat and deep attribute traversions on non-const reflected classes try to acquire a lock for the traversion.

Examples:

struct YourAttributeFunction
{
    /* item functions as needed for deep traversions */
};

YourAttributeFunction attributeFunction;
		

YourReflectedClass nonConstReflectedObject;
depthFirstForeachIncAllBaseClasses(nonConstReflectedObject, attributeFunction, InstanceVariableTag());

Here nonConstReflectedObject.getMutex() will be used to acquire a lock for the deep traversion of non-static members of YourReflectedClass.
The locktype is userconfig::LockType< YourReflectedClass, userconfig::ThreadingModel>::type (As specified in userconfig.h).

const YourReflectedClass constReflectedObject = nonConstReflectedObject;
depthFirstForeachIncAllBaseClasses(constReflectedObject, attributeFunction, InstanceVariableTag());
Here the traversion will not try to acquire any lock.

depthFirstForeachIncAllBaseClasses<YourReflectedClass>(attributeFunction);
Here userconfig::MutexInstance<ReflectedClass, userconfig::ThreadingModel>::get() will be used to acquire a lock for the deep traversion of static members of YourReflectedClass.
The locktype is userconfig::LockType<ReflectedClass, userconfig::ThreadingModel>::type.

depthFirstForeachIncAllBaseClasses<const YourReflectedClass>(attributeFunction);
Here the traversion of the static members of YourReflectedClass will not try to acquire any lock.

Last revised: September 13, 2004 Copyright 2004 Arne Adams