Using the reflective type system
The types ValueHandle
and Meta:BaseType
provide
support for reflection. The former type is a handle to a value of
an SPL type. The latter type is a meta-type that represents an SPL
type.
The ValueHandle
can be used to inspect and modify
SPL typed values.
Assume that there is an SPL tuple of type tuple<rstring
name, list<rstring> locations, tuple<rstring type, float32 value,
int32 level> info>
and you want to print the location strings
that are contained in the locations
attribute, which
is a list, and thelevel
information that is contained
in the info
attribute, which is a nested tuple. The
following is an example of a code segment.
void process(Tuple & tuple, ...) {
TupleIterator iter = tuple.findAttribute("locations");
assert(iter!=tuple.getEndIterator());
TupleAttribute locsAttrb = *iter;
ValueHandle locsHandle = locsAttrb.getValue();
assert(locsHandle.getMetaType()==Meta::Type::LIST);
List & locations = locsHandle;
for(ListIterator listIter=locations.getBeginIterator();
listIter!=locations.getEndIterator(); ++listIter) {
ValueHandle locHandle = *listIter;
assert(locHandle.getMetaType()==Meta::Type::RSTRING);
rstring & location = locHandle;
cerr << "location: " << location << endl;
}
iter = tuple.findAttribute("info");
TupleAttribute infoAttrb = *iter;
ValueHandle infoHandle = infoAttrb.getValue();
assert(infoHandle.getMetaType()==Meta::Type::TUPLE);
Tuple & info = infoHandle;
ValueHandle levelHandle = info.getAttributeValue("level");
int32 & level = levelHandle;
cerr << "level: " << level;
}
A value handle can be queried for its meta-type through the getMetaType
function,
which returns an enumeration of type SPL::Meta::Type
.
In the example, this enumeration is used to make sure that the value
handle that corresponds to the locations
attribute
is a list. When the meta-type is determined, the value handle can
be cast to a more specific type, as in List & locations
= handle;
and rstring & location = locHandle;
. When
a value handle is cast to a reference type, any changes that are performed
through the reference affect the actual value that is stored behind
the value handle. For instance, location="NY";
would
change the value of the item that is stored in the locations
list
in the example. SPL also provides a ConstValueHandle
type
for handles that do not allow modification of the values.
When the concrete type of a value is not known, sometimes discovering
the type structure by using value handles and incrementally removing
the type layers as shown so far is impractical. For instance, consider
a value of type map<list<list<rstring[12]>[4]>,int32>
.
If this map is empty, then it is not possible to discover the type
structure by just traversing its value. For such cases, SPL provides
a function BaseType::makeType
that takes any SPL
typed value or a value handle, and returns a value of BaseType
that
represents the type of the SPL value that is passed in. BaseType
sits
at the top of a class hierarchy that represents all SPL types, such as ListType
, TupleType
.
This example illustrates this concept.
using namespace SPL::Meta;
Map & mp = ...; // map<list<list<rstring[12]>[4]>,int32>
BaseType const & m0_btp = BaseType::makeType(mp);
assert(m0_btp.getMetaType()==Type::MAP);
MapType const & m0_mtp = dynamic_cast<MapType const &>(m0_btp);
BaseType const & m1_btp = m0_mtp.getKeyType();
assert(m1_btp.getMetaType()==Type::LIST);
ListType const & m1_ltp = dynamic_cast<ListType const &>(m1_btp);
BaseType const & m2_btp = m1_ltp.getElementType();
assert(m2_btp.getMetaType()==Type::BLIST);
BListType const & m2_bltp = dynamic_cast<BListType const &>(m2_btp);
BaseType const & m3_btp = m2_bltp.getElementType();
assert(m3_btp.getMetaType()==Type::BSTRING);
BStringType const & m3_bstp = dynamic_cast<BStringType const&>(m3_btp);
BaseType const & m4_btp = m0_mtp.getValueType();
assert(m4_btp.getMetaType()==Type::INT32);
SimplePrimitiveType const & m4_nptp =
dynamic_cast<SimplePrimitiveType const &>(m4_btp);
The code is greatly simplified through assertions. If a type is unknown, various switch or case statements are needed to truly handle all possibilities.