
\batchmode
% \documentclass{sig-alternate}
\documentclass{sig-strict-2.6sp}

\begin{document}
\sloppy

\title{XVF: C++ Introspection by Extensible Visitation}

\subtitle{[Extended Abstract]}

\author{\alignauthor Kurt Stephens \linebreak \affaddr{ION, Inc.}\linebreak \affaddr{5183 Pinetree Drive}\linebreak \affaddr{Delray Beach, FL, 33484}, \affaddr{USA}\email{kurtstephens@acm.org}\linebreak \linebreak May 22, 2001 (revised May 16, 2003)}

\maketitle
\begin{abstract}
  Object serialization and object inspector user interfaces are concerns that can be orthogonally implemented using introspection via meta-object protocols (MOP).  The C++ language lacks a formal meta-object protocol, although some are available as source pre-processors.  A full MOP is not necessary for many classes of problems where basic introspection is useful. This paper describes a technique: extensible visitation of objects as a basic introspection primitive.

\end{abstract}

\section{Introduction}


Introspection, the access of information about a program's construction during run-time, is valuable.  Meta-object protocols (MOP) \cite{KICZALES91} allow object-oriented systems to reify their own definition.  Some C++ MOP implementations (\cite{IGUANA}, \cite{OPENCXX}) use pre-compilation.

For common concerns, such as object serialization and object inspector user interfaces, a complete MOP is useful but not required.  Extensible visitation based on the Visitor design pattern \cite{GAMMA95} is a mechanism, similar to XDR \cite{XDR}, for interfacing different introspections with little impact to an existing C++ framework.
\section{Visitation as an Introspection Primitive}


Generic programming techniques aim to eliminate boilerplate code \cite{LAMMEL03}.  Traversal code is often the largest part of many computations.

Standard C++ \texttt{ostream} classes are visitors that produce output as a side-effect of visiting typed data.  Developers must create \texttt{ostream} visitation methods for each new application class.  Developers must create similar visitation methods for other visitors.  These methods are specialized for different visitors, yet do mostly the same thing; recursively visit all data members while side-effecting the visitor.

For example:
\begin{verbatim}

class Foo
{
 private:
  double x, y; // data members
  int i3[3];

 public:
  Foo() { ... }
  Foo(double _x, double _y) { ... }

  // Visitation Methods, one for each type of visitor.

 // ostream dump method.
 ostream &print(ostream &os)
 {
   os << "Foo(" << x ", " << y << ", ";
   os << "{ "
      << i3[0] << ", "
      << i3[1] << ", "
      << i3[2]
      << " }";
   return os << ")";
 }

 // XML output method.
 ostream &print_xml(ostream &os)
 {
   os << "<Foo>";
   os << "<x>"; print_xml(x, os); os << "</x>";
   os << "<y>"; print_xml(y, os); os << "</y>";
   os << "<i3>";
   print_xml(i3[0], os);
   print_xml(i3[1], os);
   print_xml(i3[2], os);
   os << "</i3>";
   return os << "</Foo>";
 }

 // inspector generation method.
 inspector &generate_inspector(inspector &is)
 {
   is.begin_frame("Foo", this);
   is.generate_inspector("x", &x);
   is.generate_inspector("y", &y);
   is.begin_frame("i3[]", &i3);
   is.generate_inspector("0", &i3[0]);
   is.generate_inspector("1", &i3[1]);
   is.generate_inspector("2", &i3[2]);
   is.end_frame(&i3);
   is.end_frame(this);
   return is;
 }

 // XDR support method
 int xdr(XDR *xdr)
 {
   return
   xdr_double(xdr, &x) &&
   xdr_double(xdr, &y) &&
   xdr_int(xdr, &i3[0]) &&
   xdr_int(xdr, &i3[1]) &&
   xdr_int(xdr, &i3[2]);
 }
 // ... other visitor types
}


\end{verbatim}



In the example above, more visitation methods are needed as the application classes (visitees) interface with more visitors.  Adding, removing or renaming data members becomes a maintenance problem, since each visitation method must be updated.  Likewise, adding new visitations becomes difficult as the application grows, since each application class must be updated.

If the number of application classes in a system is \texttt{N} and the number of visitor classes is \texttt{M}, the complexity of the application-visitor interfaces will be \texttt{N * M}, if visitor-specific methods are implemented for each application class.  If a single generic visitation method is used for each visitor class, the complexity of the application-visitor interfaces will be \texttt{N + M}.

Ideally a single visitation method suffices for most types of visitation.  Essentially we want to move the complexity from the visited classes to the visitors, since the number of visitor classes will be small compared to the visited classes.  Visitor classes tend to interface auxiliary systems and protocols, such as XML and other I/O systems, and change less frequently than the application classes.
\section{XVF}


XVF (eXtensible Visitation Framework) is a C++ template-based framework for developing visitors and generic visitation methods.  In XVF, a generic introspection visitor is messaged with type, naming and layout information about the visited objects.  The visitor consumes the introspective messages and controls the recursion during visitation.  The visitor's introspection methods are virtual, such that any visitor can be used in any visitation traversal.  The set of introspection methods in the visitor closely follows a decomposition of the data types in C++: structures (classes), pointers, arrays and intrinsic types (\texttt{char}, \texttt{int}, \texttt{double}).
\subsection{Visitor classes}


In XVF, Visitors are sub-classes of \texttt{XVFVisitor}.  \texttt{XVFVisitor} has methods for keeping track of what object is being visited and what members are being visited.  Each intrinsic type (e.g. \texttt{char}, \texttt{int}, \texttt{double}) has a visitation method specialized for it in the visitor class.

Visitors are messaged with information about the visitee during visitation traversal.
\subsection{Visitee type objects}


In XVF, the \texttt{XVFType} class provides basic type introspection: type name, type size and allocation and assignment methods.

\texttt{XVFType} objects are constructed dynamically by class templates instantiated by template functions.  There are five \texttt{XVFType} templates: intrinsic types (\texttt{char}, \texttt{int}, \texttt{unsigned long}), abstract classes (non-instantiable classes), concrete classes (instantiable classes), pointers, and arrays.

The \texttt{XVFTypeIntrinsic<T>} template creates \texttt{XVFType} classes for intrinsic types.  The templates \texttt{XVFTypeClass<T>} and \texttt{XVFTypeAbstract<T>} create type objects for instantiable and abstract classes, respectively.  Type objects for intrinsic types are created "by hand" in XVF.  Pointer and array type objects are constructed by \texttt{XVFTypePtr<T>} and \texttt{XVFTypeArray<T>}, respectively.  \texttt{XVFType} templates are never instantiated by the user of XVF, but are created automatically by the instantiation of \texttt{xvf\symbol{95}type(T*)} template functions based on pointers to type \texttt{T}.

Each type object implements a virtual \texttt{visit(void *data, XVFVisitor *V)} method that is specialized by the type object template to call a template function \texttt{xvf\symbol{95}visit((T *) data, V)};

For example, if \texttt{aFoo} is an instance of class \texttt{Foo}, the template function call, \texttt{xvf\symbol{95}type(&aFoo)}, returns the \texttt{XVFType} type object for the object instance \texttt{aFoo}.  Likewise, the static method, \texttt{XVFType::type("Foo")}, returns the same \texttt{XVFtype} type object for the class named \texttt{"Foo"}.

The type objects are used to aid the visitors when visiting each class.  For example: a XML input visitor may need to construct a new object based on a XML tag name.
\subsection{Visitor/Visitee Interface}


Visitee classes are not sub-classes of a special "Visitee" class.  They are "glued" to the XVF library by static type polymorphic functions:

\texttt{XVFType *xvf\symbol{95}type(T *x)}

returns the \texttt{XVFType} object for type \texttt{T}.

\texttt{T *xvf\symbol{95}alloc(T *dummy)}

allocates an object of type \texttt{T}.

\texttt{void xvf\symbol{95}dealloc(T *x)}

deallocates an object of type \texttt{T}.

\texttt{void xvf\symbol{95}visit(T *x, XVFVisitor *V, int opts)}

recursively visits an object of type \texttt{T} with visitor \texttt{V}.

Note: XVF does not dispatch using \texttt{const &T} because then \texttt{void} could not be handled in a unified manner and because data are visited by address.
\subsection{Visitation Methods}


Any type \texttt{T} that implements a \texttt{xvf\symbol{95}type(T *x)} and \texttt{xvf\symbol{95}visit(T *x, XVFVisitor *V, int opts)} (the \texttt{opts} argument is explained later) functions can be visited by any \texttt{XVFVisitor} object.

XVF supplies macros for constructing a class' visitation method and type object accessor functions.

For example:
\begin{verbatim}
// Declare xvf_type(Foo *)
XVF_CLASS_BEGIN(Foo);

class Foo {
  double x, y;
  int i3[3];
public:
  Foo() { ... }
  Foo(double x, double y) { ... }

  // xvf_type() support
  XVF_CLASS_METHODS(XVF_);

  // xvf_visit() support
  XVF_CLASS_VISIT_BEGIN_INLINE(Foo)
  {
     XVF_MEMB(x);
     XVF_MEMB(y);
     XVF_MEMB(i3);
  }
  XVF_CLASS_VISIT_END()
};

// Define xvf_visit(Foo *)
XVF_CLASS_END(Foo);

// Define xvf_type(Foo *)
XVF_CLASS_INSTANCE(Foo);

\end{verbatim}


\subsection{Visitor Messages}


The visitor is messaged with information about the visited object during traversal.  The visitor can dynamically control recursion for any visitation member.  The \texttt{XVF\symbol{95}MEMB()} macro above expands into messages to the visitor.

For example: any visitor \texttt{V} visiting \texttt{Foo}\texttt{F} will have the following methods called on it:
\begin{verbatim}
xvf_visit(&F, V);

\end{verbatim}



is equivalent to:
\begin{verbatim}
V->this_begin(xvf_type(&F), &F, opts);
 if ( V->memb(xvf_type(&F.x), "x", &F.x, opts) ) {
   V->memb_begin(xvf_type(&F.x), "x", &F.x, opts);
    xvf_visit(&F.x, V, opts);
   V->memb_end(xvf_type(&F.x), "x", &F.x, opts);
 }
 if ( V->memb(xvf_type(&F.y), "y", &F.y, opts) ) {
   V->memb_begin(xvf_type(&F.y), "y", &F.y, opts);
    xvf_visit(&F.y, V, opts);
   V->memb_end(xvf_type(&F.y), "y" &F.y, opts);
 }
 if ( V->memb(xvf_type(&F.i3), "i3", &F.y, opts) ) {
   V->memb_begin(xvf_type(&F.i3), "i3", &F.y, opts);
     V->arry_begin(xvf_type(&F.i3),
                   xvf_type(&F.i3[0]),
                   &F.i3, 3, opts);
       V->elem_begin(0, opts);
         xvf_visit(&F.i3[0], V, opts);
       V->elem_end(0, opts);
       V->elem_begin(1, opts);
         xvf_visit(&F.i3[1], V, opts);
       V->elem_end(1, opts);
       V->elem_begin(2, opts);
         xvf_visit(&F.i3[2], V, opts);
       V->elem_end(3, opts);
     V->arry_end(xvf_type(&F.i3),
                 xvf_type(&F.i3[0]),
                 &F.i3, 3, opts);
   V->memb_end(xvf_type(&F.i3), "i3" &F.y, opts);
 }
V->this_end();

\end{verbatim}


\section{Handling const-ness}


The \texttt{opts} argument to the \texttt{visit} functions relays \texttt{const}-ness to the visitor without requiring different routines and type objects for \texttt{const} and non-\texttt{const} visitation.

If \texttt{opts == XVF\symbol{95}NON\symbol{95}CONST} in \texttt{V->visit(T *data, int opts)}, \texttt{V->visit()} has license to modify \texttt{*data}.

For example: an inspector user-interface visitor may generate an editable or non-editable user-interface field depending if \texttt{opts == XVF\symbol{95}NON\symbol{95}CONST} or \texttt{opts == XVF\symbol{95}CONST}.
\section{Handling visit-by-value}


Sometimes the visitation semantics of a class' members should be through a pair of accessor methods or functions, rather than directly on an object data member.

For example:
\begin{verbatim}
XVF_CLASS_BEGIN(Temperature);
class Temperature {
  private:
    double _f; // Fahrenheit: f = (c * 1.8) + 32
    double _c; // Celsius:    c = (f - 32) / 1.8

  public:
  Temperature() { celsius(0); }

  // Getter, setter.
  double fahrenheit() const { return _f; }
  void fahrenheit(double x) {
    _f = x; _c = (_f - 32) / 1.8;
   }

  // Getter, setter.
  double celsius() const { return _c; }
  void celsius(double x) {
    _c = x; _f = _c * 1.8 + 32;
  }

  // Getter, setter.
  // Note: different setter name style
  double kelvin() const { return _c + 273.15; }
  void set_kelvin(double x) {
    celsius(x - 273.15);
  }

  XVF_CLASS_METHODS(XVF_);
  XVF_CLASS_VISIT_BEGIN_INLINE(Temperature)
  {
     // Visit by accessor code
     XVF_ACC_T("fahrenheit", // name
               double,       // type
               _xvfv_this->fahrenheit(),
                             // getter
               _xvfv_this->fahrenheit(XVF_TEMP)
	                     // setter
     );

     // Visit by accessor names using
     //   shorthand for:
     // getter: _xvfv_this->celsius()
     // setter: _xvfv_this->celsius(XVF_TEMP)
     XVF_ACC_T_M("celsius",
               double,
               celsius,
               celsius
     );

     XVF_ACC_T_M("kelvin",
               double,
               kelvin,
               set_kelvin
     );

  }
  XVF_CLASS_VISIT_END()
};
XVF_CLASS_END(Temperature);
XVF_CLASS_INSTANCE(Temperature);

\end{verbatim}



If any visitor updates the \texttt{"fahrenheit"}, \texttt{"celsius"} or \texttt{"kelvin"} members of a \texttt{Temperature} object, the Fahrenheit, Celsius and Kelvin values will be synchronized through the getter and setter methods in \texttt{Temperature}.
\section{Visitation Attributes}


A visitation method can relay visitor-specific information using visitation attributes.

Imagine a visitor that needs to know how each member is protected in a C++ class:
\begin{verbatim}
...
class Bar {
private:
  int a; // a is private.
protected:
  float b; // a is protected.
public:
  char *c; // c is public.

  Bar(...)

  XVF_CLASS_VISIT_BEGIN_INLINE(Bar)
  {
    // Save and set attribute value.
    XVF_ATTR_BEGIN("C++:protection", "private");
    XVF_MEMB(a);

    // Set attribute value.
    XVF_ATTR("C++:protection", "protected");
    XVF_MEMB(b);

    XVF_ATTR("C++:protection", "public");
    XVF_MEMB(c);

    // Restore attribute value.
    XVF_ATTR_END("C++:protection");
  }
  XVF_CLASS_VISIT_END();
};
...

\end{verbatim}



The specialized visitor will check the attribute named \texttt{"C++:protection"} for its value and produce results accordingly.
\section{Examples}


Below are sample uses of visitor objects using the same visit methods for class \texttt{Foo}.  The visitor code is not presented here.
\subsection{A Structured Data Dumper}


A structured data visitor writes a human-readable representation to an \texttt{ostream}.
\begin{verbatim}
XVF_Dump_Out<ostream> xvf(cout);
Foo p(1, 2);

xvfv << p;

\end{verbatim}


\subsection{An Archiver}


An archiver visitor writes a machine-readable representation to an \texttt{ostream}.
\begin{verbatim}
XVF_Archive_Out<ostream> xvfv(cout);
Foo p(1, 2);

xvfv << p;

\end{verbatim}


\subsection{XML I/O}


An XML output visitor writes objects as an XML stream.
\begin{verbatim}
XVF_XML_Out<ostream> xvfv(cout);
Foo p(1, 2);

xvfv << p;

\end{verbatim}



An XML input visitor reads an XML stream into a object.
\begin{verbatim}
XVFV_XML_In<istream> xvfv(cin);
Foo p;

xvfv >> p;

\end{verbatim}


\subsection{Dynamic GUI generation}


An inspector visitor generates TCL/TK code to create an inspector GUI.
\begin{verbatim}
Tcl_Interp *interp;
XVF_TK_Inspector xvfv(interp);
Foo p(1, 2);

xvfv << p;

\end{verbatim}


\begin{figure}
\centering
\epsfig{file=xvf_paper_tkinsp.eps}
\caption{TK widget generated by XVF\symbol{95}TK\symbol{95}Inspector.
}
\end{figure}

\subsection{Reflective Accessors}


These accessor visitors apply getter and setter methods by name.
\begin{verbatim}
XVF_Getter xvfg;
Foo p(1, 2);
double py;

xvfg(&p, xvf_type(&p), "y", &py); // py = p.y

XVF_Setter xvfs;
xvfs(&p, xvf_type(&p), "x", &py); // p.x = py

\end{verbatim}


\subsection{XDR Bridge}


This visitor provides XDR services.
\begin{verbatim}
XDR *xdr;
XVF_XDR xvfv(xdr);

xvfv << p;

\end{verbatim}


\section{Related Work}


External Data Representation (XDR) \cite{XDR} uses generic visitation for encoding, decoding and freeing C objects.  XDR visitors cannot be sub-classed directly and do not provide any mechanisms for XDR visitors to determine member names.  XDR is used primarily for Remote Procedure Calls (RPC) \cite{RPC}.

OpenC++ \cite{OPENCXX} provides introspection using pre-compiler techniques.  Iguana \cite{IGUANA} seems to be based on pre-compiler techniques as well, but no public implementations are offered.

\cite{LAMMEL03} discusses generic traversal combinator generation for generic programming support.
\section{Future Work}


Namespaces, enumerations, bit-fields, unions, function pointers and methods are not handled.   Class versioning for backward compatibility is not handled.   A pre-processor to parse members from class definitions to generate and insert \texttt{xvf\symbol{95}visit()} methods would be helpful; OpenC++ or SWIG \cite{SWIG} might be applicable.  A C interface for legacy code may also be useful.
\section{Conclusion}


This paper describes a method for basic introspection in C++ using the Visitor design pattern.  A prototype implementation of XVF is available at \texttt{URL: http://kurtstephens.com/pub/xvf}.
\bibstyle{}
\begin{thebibliography}{99}



\bibitem{SWIG}
  D. Beazley.  {\em Simplified Wrapper and Interface Generator Homepage}, URL: \texttt{http://www.swig.org}, 2003.

\bibitem{IGUANA}
  V. Cahill.  {\em The Iguana Project Homepage}, URL: \texttt{http://www.dsg.cs.tcd.ie/\symbol{126}coyote}, 2003.

\bibitem{OPENCXX}
  S. Chiba.  {\em OpenC++ Homepage}, URL: \texttt{http://www.csg.is.titech.ac.jp/\symbol{126}chiba/openc++.html}, 2003.

\bibitem{GAMMA95}
  E. Gamma, R. Helm, R. Johnson and J. Vlissides.  {\em Design Patterns}, Addison-Wesley, 1995.

\bibitem{KICZALES91}
  G. Kiczales.  {\em The Art of the Metaobject Protocol}, MIT Press, 1991.

\bibitem{LAMMEL03}
  R. Lammel and S. Jones.  Scrap Your Boilerplate: A Practical Design Pattern for Generic Programming.    In {\em ACM SIGPLAN Workshop on Types in Language Design and Implementation (TLDI 2003)}, pages 26-37, ACM, 2003.

\bibitem{RPC}
  R. Srinivasan.  {\em RFC 1831: RPC: Remote Procedure Call Protocol Specification Version 2}, URL: \texttt{http://www.ietf.org/rfc/rfc1831.txt}, 1995.

\bibitem{XVF}
  K. Stephens.  {\em XVF Package Homepage}, ION, Inc., URL: \texttt{http://kurtstephens.com/pub/xvf}, 2001.

\bibitem{XDR}
  Sun Microsystems, Inc.  {\em RFC 1014: XDR: External Data Representation Standard}, URL: \texttt{http://www.ietf.org/rfc/rfc1014.txt}, 1987.

\end{thebibliography}

\balancecolumns
\end{document}
