Difference between revisions of "Talk:V4 CA Interfaces"

From EPICSWIKI
Line 14: Line 14:
createAllPropertiesReadRequest() method.  I'm only looking for you to  
createAllPropertiesReadRequest() method.  I'm only looking for you to  
support "*", no pattern matching or regex stuff.
support "*", no pattern matching or regex stuff.


Some comments from Jeff Hill:
Some comments from Jeff Hill:
Line 22: Line 21:
There may be legitimate situations where the property catalog egg must come before the property catalog chicken. Furthermore, it might be quite inconvenient from a memory management perspective to require an instance of an array before it is really used. I think that this negative could be perhaps minimized if we state in the CA manual that the array bounds alone will be examined, and the array elements will not be traversed, when scanning a property catalog to learn its structure.
There may be legitimate situations where the property catalog egg must come before the property catalog chicken. Furthermore, it might be quite inconvenient from a memory management perspective to require an instance of an array before it is really used. I think that this negative could be perhaps minimized if we state in the CA manual that the array bounds alone will be examined, and the array elements will not be traversed, when scanning a property catalog to learn its structure.


Probably the only negative associated with adding a property catalog structure traverse capability to the interface would be that the application would need to provide one additional function. They are already providing an immutable traverse, a mutable traverse function, and an immutable find function. What is not really right is that all three of the traverse functions are nearly identical. Personally, I don’t like to see common code managed with cut and paste.
Probably the only negative associated with adding a property catalog structure traverse capability to the interface would be that the application would need to provide one additional function. They are already providing an immutable traverse, a mutable traverse function, and an immutable find function. What is vexing is that all three of the traverse functions are nearly identical. Personally, I don’t like to see common code managed with cut and paste. I am even less fond of that eventuality should it be repeated for many, many data structures in a proliferation of applications.
 
So I had a look at what level of Data Access library support might be provided so that they need write the guts of the traverse function once. The following is an example of how they might structure their application. There are still three traverse functions because cross library binding requires the virtual base class interfaced technique, but now they can use a template to implement the traversing only once.
 
This level of complication appears to be reasonable for end user applications.  


So I had a look at what level of Data Access library support might be provided so that they might avoid needing to write three traverse functions. The following is an example of how they might structure their application. This level of complication appears to be reasonable for end user applications.
<pre>


PropertyId propertyX;
PropertyId propertyX;
PropertyId propertyY;
PropertyId propertyY;
PropertyId propertyZ;
PropertyId propertyI;
class MyContainer : private PropertyCatalog {
public:


class MyContainer :  
private:
    private PropertyCatalog {
     int x;
     int x;
     float y;
     float y;
    double z;
    char i;
     static void traverse (  
     static void traverse (  
         PropertyDescriptionViewer & );
         PropertyDescriptionViewer & );
Line 47: Line 56:


template < class REFERENCE, class MANIPULATOR >
template < class REFERENCE, class MANIPULATOR >
void MyContainer::traverseTempl (  
inline void MyContainer::traverseTempl (  
     const REFERENCE & ref, MANIPULATOR & manipulator )
     const REFERENCE & ref, MANIPULATOR & manipulator )
{
{
     manipulator.reveal (  
     ref.reveal (  
         ref.propertyFactory ( propertyX, & MyContainer::x ) );
         manipulator, propertyX, & MyContainer::x );
     manipulator.reveal (  
    ref.reveal (  
         ref.propertyFactory ( propertyY, & MyContainer::y ) );
        manipulator, propertyY, & MyContainer::y );
     ref.reveal (  
         manipulator, propertyZ, & MyContainer::x );
    ref.reveal (  
        manipulator, propertyI, & MyContainer::i );
}
}


Line 94: Line 107:
}
}


Here is a summary of the changes:
</pre>
* A new "static void traverse ( PropertyDescriptionViewer & );" in the application. This interface might be bound at run time with an ordinary function pointer, and not bound through a pure virtual base. Since data description is accessed through a static member function then ordinary function pointers appear to be a plausible way to bind to this interface. There may not be justification to juxtapose an additional layer of overhead for a virtual interface. That might be necessary only if there was more than one function of this type.
 
Here are the interface details.


* To allow all three traverse functions to be implemented with a template the properties are revealed using three new property handle types corresponding to the three types of traversal supported.
<pre>


Here are the slightly revised Data Access interfaces.
class PropertyId;
class ArraySegment;
class StringSegment;
class EnumStateSet;
class PropertyCatalog;
class PropertyCatalog;
class Time;


enum propertyHandleType {
class PropertyId {
    phMutable,
    phImmutable,
    phDescription
};
};


template < propertyHandleType PHT, class T >
extern class PropertyCatalog & voidCatalog;
class PropertyHandle;


template < class T >
class PropertyViewer {
class PropertyHandle < phMutable, T > {
public:
public:
     PropertyHandle (  
     virtual void reveal ( const PropertyId &,
         const PropertyId & id, T & value,   
         const double &, const PropertyCatalog & = voidCatalog )  = 0;
         PropertyCatalog & subordinate = voidContainer );
    virtual void reveal ( const PropertyId &,  
     T & value () const;
        const int &, const PropertyCatalog & = voidCatalog ) = 0;
     const PropertyId & id () const;
    virtual void reveal ( const PropertyId &,
     PropertyCatalog & subordinate () const;
         const unsigned int &, const PropertyCatalog & = voidCatalog ) = 0;
private:
     virtual void reveal ( const PropertyId &,
    T & _scalar;
        const long &, const PropertyCatalog & = voidCatalog )  = 0;
     const PropertyId & _id;
    virtual void reveal ( const PropertyId &,
     PropertyCatalog & _subordinateProperties;
        const unsigned long &, const PropertyCatalog & = voidCatalog ) = 0;
     virtual void reveal ( const PropertyId &,
        const Time &, const PropertyCatalog & = voidCatalog ) = 0;
     virtual void reveal ( const PropertyId &,
        const StringSegment &, const PropertyCatalog & = voidCatalog ) = 0;
    virtual void reveal ( const PropertyId &,
        const EnumStateSet & )  = 0;
     virtual void reveal ( const PropertyId &,
        const ArraySegment &, const PropertyCatalog & = voidCatalog )  = 0;
     virtual void reveal ( const PropertyId &,
        const PropertyCatalog & )  = 0;
};
};


template < class T >  
template < class T >
class PropertyHandle < phImmutable, T > {
class TypedVoid {
public:
    PropertyHandle (
        const PropertyId & id, const T & value, 
        const PropertyCatalog & subordinate = voidContainer );
    const T & value () const;
    const PropertyId & id () const;
    const PropertyCatalog & subordinate () const;
private:
    const T & _scalar;
    const PropertyId & _id;
    const PropertyCatalog & _subordinateProperties;
};
};


template < class T >
class PropertyDescriptionViewer {
class PropertyHandle < phDescription, T > {
public:
public:
     PropertyHandle ( const PropertyId & id,   
     virtual void reveal ( const PropertyId &,  
         const PropertyCatalog & = voidContainer );
        TypedVoid < float > &, const PropertyCatalog & = voidCatalog )  = 0;
     const PropertyId & id () const;
    virtual void reveal ( const PropertyId &,
     const PropertyCatalog & subordinate () const;
        TypedVoid < double > &, const PropertyCatalog & = voidCatalog )  = 0;
private:
    virtual void reveal ( const PropertyId &,
     const PropertyId & _id;
        TypedVoid < char > &, const PropertyCatalog & = voidCatalog )  = 0;
     const PropertyCatalog & _subordinateProperties;
    virtual void reveal ( const PropertyId &,
        TypedVoid < signed char > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &,
        TypedVoid < unsigned char > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &,
        TypedVoid < short > &, const PropertyCatalog & = voidCatalog ) = 0;
    virtual void reveal ( const PropertyId &,
         TypedVoid < unsigned short > &, const PropertyCatalog & = voidCatalog ) = 0;
     virtual void reveal ( const PropertyId &,
        TypedVoid < int > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &,
        TypedVoid < unsigned int > &, const PropertyCatalog & = voidCatalog ) = 0;
    virtual void reveal ( const PropertyId &,
        TypedVoid < long > &, const PropertyCatalog & = voidCatalog )  = 0;
     virtual void reveal ( const PropertyId &,
        TypedVoid < unsigned long > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &,
        TypedVoid < Time > &, const PropertyCatalog & = voidCatalog ) = 0;
    virtual void reveal ( const PropertyId &,
        TypedVoid < StringSegment > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &,
        TypedVoid < EnumStateSet > & )  = 0;
     virtual void reveal ( const PropertyId &,
        TypedVoid < ArraySegment > &, const PropertyCatalog & = voidCatalog )  = 0;
     virtual void reveal ( const PropertyId &,
        TypedVoid < PropertyCatalog > & )  = 0;
};
};


template <
class PropertyManipulator {
    propertyHandleType PHT,
    template < propertyHandleType PHT, class T > class PROP_HANDLE >
class PropertyManipulatorBase {
public:
public:
     virtual void reveal ( const PROP_HANDLE < PHT, float > & )  = 0;
     virtual void reveal ( const PropertyId &,  
     virtual void reveal ( const PROP_HANDLE < PHT, double > & )  = 0;
        float &, const PropertyCatalog & = voidCatalog )  = 0;
     virtual void reveal ( const PROP_HANDLE < PHT, char > & ) = 0;  
     virtual void reveal ( const PropertyId &,  
     virtual void reveal ( const PROP_HANDLE < PHT, signed char > & ) = 0;  
        double &, const PropertyCatalog & = voidCatalog )  = 0;
     virtual void reveal ( const PROP_HANDLE < PHT, unsigned char > & ) = 0;  
     virtual void reveal ( const PropertyId &,  
     virtual void reveal ( const PROP_HANDLE < PHT, short > & ) = 0;  
        char &, const PropertyCatalog & = voidCatalog ) = 0;
     virtual void reveal ( const PROP_HANDLE < PHT, unsigned short > & ) = 0;  
     virtual void reveal ( const PropertyId &,  
     virtual void reveal ( const PROP_HANDLE < PHT, int > & ) = 0;  
        signed char &, const PropertyCatalog & = voidCatalog ) = 0;
     virtual void reveal ( const PROP_HANDLE < PHT, unsigned int > & ) = 0;  
     virtual void reveal ( const PropertyId &,  
     virtual void reveal ( const PROP_HANDLE < PHT, long > & ) = 0;  
        unsigned char &, const PropertyCatalog & = voidCatalog ) = 0;
     virtual void reveal ( const PROP_HANDLE < PHT, unsigned long > & ) = 0;  
     virtual void reveal ( const PropertyId &,  
     virtual void reveal ( const PROP_HANDLE < PHT, Time > & ) = 0;  
        short &, const PropertyCatalog & = voidCatalog ) = 0;
     virtual void reveal ( const PROP_HANDLE < PHT, StringSegment > & ) = 0;  
     virtual void reveal ( const PropertyId &,  
     virtual void reveal ( const PROP_HANDLE < PHT, EnumStateSet > & ) = 0;  
        unsigned short &, const PropertyCatalog & = voidCatalog ) = 0;
     virtual void reveal ( const PROP_HANDLE < PHT, ArraySegment > & ) = 0;  
     virtual void reveal ( const PropertyId &,  
     virtual void reveal ( const PROP_HANDLE < PHT, PropertyCatalog > & ) = 0;  
        int &, const PropertyCatalog & = voidCatalog ) = 0;
};
     virtual void reveal ( const PropertyId &,  
 
        unsigned int &, const PropertyCatalog & = voidCatalog ) = 0;
class PropertyManipulator :
     virtual void reveal ( const PropertyId &,  
    public PropertyManipulatorBase < phMutable, PropertyHandle > {
        long &, const PropertyCatalog & = voidCatalog ) = 0;
};
     virtual void reveal ( const PropertyId &,  
 
        unsigned long &, const PropertyCatalog & = voidCatalog ) = 0;
class PropertyViewer :
     virtual void reveal ( const PropertyId &,  
    public PropertyManipulatorBase < phImmutable, PropertyHandle > {
        Time &, const PropertyCatalog & = voidCatalog ) = 0;
};
     virtual void reveal ( const PropertyId &,  
 
        StringSegment &, const PropertyCatalog & = voidCatalog ) = 0;
class PropertyDescriptionViewer :
     virtual void reveal ( const PropertyId &,  
    public PropertyManipulatorBase < phDescription, PropertyHandle > {
        EnumStateSet & ) = 0;
     virtual void reveal ( const PropertyId &,  
        ArraySegment &, const PropertyCatalog & = voidCatalog ) = 0;
     virtual void reveal ( const PropertyId &,  
        PropertyCatalog & ) = 0;
};
};


Line 197: Line 236:
         const PropertyId & id, PropertyViewer & ) const = 0;
         const PropertyId & id, PropertyViewer & ) const = 0;
};
};
// ----------------- void property catalog implementation ---------------------------
class VoidContainer : public PropertyCatalog {
    void traverse (
        PropertyManipulator & ) {}
    void traverse (
        PropertyViewer & ) const {}
    // false returned when the property does not exist, otherwise true
    bool find (
        const PropertyId & id, PropertyViewer & ) const
    {
        return false;
    }
};
VoidContainer aVoidContainer;
class PropertyCatalog & voidCatalog = aVoidContainer;
// --------------------------- begin reference implemenation --------------------------
template < class T >
class reference
{
public:
    reference ( T & ref ) :
      _ref ( ref )
    {
    }
    template < class M >
    void reveal (
        PropertyManipulator & manipulator,
        const PropertyId & id, M ( T :: * p ),
        PropertyCatalog & subordinates = voidCatalog ) const
    {
        manipulator.reveal (
            id, _ref.*p, subordinates );
    }
private:
    T & _ref;
};
template < class T >
class reference < const T >
{
public:
    reference ( const T & ref ) :
      _ref ( ref )
    {
    }
    template < class M >
    void reveal (
        PropertyViewer & viewer,
        const PropertyId & id, M ( T :: * p ),
        const PropertyCatalog & subordinates = voidCatalog ) const
    {
        viewer.reveal (
            id, _ref.*p, subordinates );
    }
private:
    const T & _ref;
};
template <>
class reference < void >
{
public:
    template < class T, class M >
    void reveal (
        PropertyDescriptionViewer & viewer,
        const PropertyId & id, M ( T :: * p ),
        const PropertyCatalog & subordinates = voidCatalog ) const
    {
        viewer.reveal (
            id, TypedVoid < M > (), subordinates );
    }
};
</pre>

Revision as of 19:21, 20 May 2005

Some comments from Andrew Johnson:

In your presentation about CA V4, you included the method channel::createAllPropertiesReadRequest(). I agree that we need a way to be able to read all of the properties available from the server for a particular PV name, but I want more flexibility than just being able to put that wild-card at the top of my request.

I think we need the ability to be able to subscribe with a property catalog having a specific set of properties at one level but to wild-card a sub-property catalog at some level below. Is this currently possible? If not, please consider this a request to add that capability, which might then remove the need for the seperate createAllPropertiesReadRequest() method. I'm only looking for you to support "*", no pattern matching or regex stuff.

Some comments from Jeff Hill:

During our meeting I raised a question; do we may need a Data Access interface allowing traversal of the structure of the property hierarchy, learning the native type of the properties, but not require instances of the properties?

There may be legitimate situations where the property catalog egg must come before the property catalog chicken. Furthermore, it might be quite inconvenient from a memory management perspective to require an instance of an array before it is really used. I think that this negative could be perhaps minimized if we state in the CA manual that the array bounds alone will be examined, and the array elements will not be traversed, when scanning a property catalog to learn its structure.

Probably the only negative associated with adding a property catalog structure traverse capability to the interface would be that the application would need to provide one additional function. They are already providing an immutable traverse, a mutable traverse function, and an immutable find function. What is vexing is that all three of the traverse functions are nearly identical. Personally, I don’t like to see common code managed with cut and paste. I am even less fond of that eventuality should it be repeated for many, many data structures in a proliferation of applications.

So I had a look at what level of Data Access library support might be provided so that they need write the guts of the traverse function once. The following is an example of how they might structure their application. There are still three traverse functions because cross library binding requires the virtual base class interfaced technique, but now they can use a template to implement the traversing only once.

This level of complication appears to be reasonable for end user applications.


PropertyId propertyX;
PropertyId propertyY;
PropertyId propertyZ;
PropertyId propertyI;

class MyContainer : private PropertyCatalog {
public:

private:
    int x;
    float y;
    double z;
    char i;
    static void traverse ( 
        PropertyDescriptionViewer & );
    void traverse ( 
        PropertyManipulator & );
    void traverse ( 
        PropertyViewer & ) const;
    bool find ( 
        const PropertyId & id, PropertyViewer & ) const;
    template < class REFERENCE, class MANIPULATOR >
    static void traverseTempl ( 
        const REFERENCE &, MANIPULATOR & );
};

template < class REFERENCE, class MANIPULATOR >
inline void MyContainer::traverseTempl ( 
    const REFERENCE & ref, MANIPULATOR & manipulator )
{
    ref.reveal ( 
        manipulator, propertyX, & MyContainer::x );
    ref.reveal ( 
        manipulator, propertyY, & MyContainer::y );
    ref.reveal ( 
        manipulator, propertyZ, & MyContainer::x );
    ref.reveal ( 
        manipulator, propertyI, & MyContainer::i );
}

void MyContainer::traverse ( 
    PropertyManipulator & manipulator ) 
{
    MyContainer::traverseTempl ( 
        reference < MyContainer > ( *this ), manipulator );
}

void MyContainer::traverse ( 
    PropertyViewer & viewer ) const 
{
    MyContainer::traverseTempl ( 
        reference < const MyContainer > ( *this ), viewer );
}

void MyContainer::traverse ( 
    PropertyDescriptionViewer & viewer )
{
    MyContainer::traverseTempl ( reference < void > (), viewer );
}
    
bool MyContainer::find ( 
    const PropertyId & id, 
    PropertyManipulator < Property > & manipulator ) const 
{
    bool status = false;
    if ( id == propertyX ) {
    	manipulator.reveal ( 
    	    Property < const int > ( propertyX, this->x ) );
        status = true;
    }
    else ( id == propertyY ) {
    	manipulator.reveal ( 
    	    Property < const int > ( propertyY, this->y ) );
        status = true;
    }
    return status;
}

Here are the interface details.


class PropertyId;
class ArraySegment;
class StringSegment;
class EnumStateSet;
class PropertyCatalog;
class PropertyCatalog;
class Time;

class PropertyId {
};

extern class PropertyCatalog & voidCatalog;

class PropertyViewer {
public:
    virtual void reveal ( const PropertyId &, 
        const double &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        const int &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        const unsigned int &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        const long &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        const unsigned long &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        const Time &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        const StringSegment &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        const EnumStateSet & )  = 0;
    virtual void reveal ( const PropertyId &, 
        const ArraySegment &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        const PropertyCatalog & )  = 0;
};

template < class T >
class TypedVoid {
};

class PropertyDescriptionViewer {
public:
    virtual void reveal ( const PropertyId &, 
        TypedVoid < float > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < double > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < char > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < signed char > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < unsigned char > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < short > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < unsigned short > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < int > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < unsigned int > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < long > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < unsigned long > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < Time > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < StringSegment > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < EnumStateSet > & )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < ArraySegment > &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        TypedVoid < PropertyCatalog > & )  = 0;
};

class PropertyManipulator {
public:
    virtual void reveal ( const PropertyId &, 
        float &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        double &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        char &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        signed char &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        unsigned char &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        short &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        unsigned short &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        int &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        unsigned int &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        long &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        unsigned long &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        Time &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        StringSegment &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        EnumStateSet & )  = 0;
    virtual void reveal ( const PropertyId &, 
        ArraySegment &, const PropertyCatalog & = voidCatalog )  = 0;
    virtual void reveal ( const PropertyId &, 
        PropertyCatalog & )  = 0;
};

class PropertyCatalog {
public:
    virtual void traverse ( 
        PropertyManipulator & ) = 0;
    virtual void traverse ( 
        PropertyViewer & ) const = 0;
    // false returned when the property does not exist, otherwise true
    virtual bool find ( 
        const PropertyId & id, PropertyViewer & ) const = 0;
};

// ----------------- void property catalog implementation ---------------------------

class VoidContainer : public PropertyCatalog {
    void traverse ( 
        PropertyManipulator & ) {}
    void traverse ( 
        PropertyViewer & ) const {}
    // false returned when the property does not exist, otherwise true
    bool find ( 
        const PropertyId & id, PropertyViewer & ) const 
    {
        return false;
    }
};

VoidContainer aVoidContainer;
class PropertyCatalog & voidCatalog = aVoidContainer;

// --------------------------- begin reference implemenation --------------------------

template < class T >
class reference
{
public:
    reference ( T & ref ) : 
      _ref ( ref ) 
    {
    }
    template < class M >
    void reveal ( 
        PropertyManipulator & manipulator,
        const PropertyId & id, M ( T :: * p ), 
        PropertyCatalog & subordinates = voidCatalog ) const
    {
        manipulator.reveal (
            id, _ref.*p, subordinates );
    }
private:
    T & _ref;
};

template < class T >
class reference < const T >
{
public:
    reference ( const T & ref ) : 
      _ref ( ref ) 
    {
    }
    template < class M >
    void reveal ( 
        PropertyViewer & viewer,
        const PropertyId & id, M ( T :: * p ), 
        const PropertyCatalog & subordinates = voidCatalog ) const
    {
        viewer.reveal (
            id, _ref.*p, subordinates );
    }
private:
    const T & _ref;
};

template <>
class reference < void >
{
public:
    template < class T, class M >
    void reveal ( 
        PropertyDescriptionViewer & viewer,
        const PropertyId & id, M ( T :: * p ), 
        const PropertyCatalog & subordinates = voidCatalog ) const
    {
        viewer.reveal (
            id, TypedVoid < M > (), subordinates );
    }
};