Node: Accessing Type Meta-Objects, Next: , Previous: Defining New Subtypes, Up: Subtypes



Accessing Type Meta-Objects

As mentioned previously all Lpp objects are of some type in the Lpp type hierarchy where each type has a Type meta-object associated with it. We call these meta objects because they contain the information about and type functionality of the ordinary Lpp objects they are associated with. There is one type meta-object for all ordinary Lpp object instances of that type.

These Type objects are first class Lpp objects and can be manipulated and accessed dynamically. For example the print methods of specific types can be accessed and set dynamically. First we show two functions for getting the type meta-object itself.

typeOf object Function

This function returns returns the type meta-object for the type of the Lpp object object.

type name Macro

This macro returns the type meta-object named name. Here are some examples:

     let typeList =
       list(type(Integer), type(Symbol), type(MyType));
     eq(typeOf(L(23)), first(typeList)) => t
     eq(typeOf(S(23)), second(typeList)) => t
     

typeName object Function

typeNameL object Function

typeName returns a char* representing the type print name of the object object. For example:

     let object = S(red);
     typeName(object) => "Symbol"
     

The typeNameL function does the same but returns an Lpp String object.

A Type meta-object contains various functions that dispatch on the type of a given object dynamically. These are similar to virtual functions but are more powerful in that they can be manipulated dynamically. Lpp provides some built in type dispatching functions for things such as printing and equality of objects.

All Lpp Type meta-objects when created have default dispatching functions generated. The user however may access these dispatching functions or set them to new dispatching functions dynamically. In general there are slots in the Type meta-object that can be accessed by functions of the form

     setTypeXXXX type data
     getTypeXXXX type
     

where XXXX refers to the kind of data being accessed in the given type where type is an Lpp Type meta-object. And setTypeXXXX sets the data and getTypeXXXX returns the data data last set. When setting data is given as nil it usually gets interpreted as setting back to the a default. This setting and getting can be done dynamically at run time. Here are some examples

     let original = getTypePrinc(type(MyType));
     setTypePrinc(type(MyType), L(MyTypePrincFunction));
     setTypePrinc(type(MyType), Nil);
     setTypePrinc(type(MyType), original);
     

The first line sets original to the current princ printer function of MyType. The second line sets the princ printer function of MyType to MyTypePrincFunction. The third line would set the princ printer function to the Lpp default. And the last line sets the princ printer function back to what it was originally.

setTypePrinc type function Function

getTypePrinc type Function

setTypePrin1 type function Function

getTypePrin1 type Function

All Lpp objects have princ and prin1 methods used by the Lpp printing family of functions and C++ stream IO of Lpp objects, See Input Output. These functions allow the user to set or get the print method of a given type where type is a Type meta-object. The functions setTypePrinc and setTypePrin1 sets the Lpp function object for the princ and prin1 methods respectively. The function argument is a function taking two arguments, first an object of type let and second a stream of type ostream&. The function should return the first argument object as both princ and prin1 do. The functions getTypePrinc and getTypePrin1 returns the last function set.

For example suppose that we had defined an Lpp class called MyClass that has two slots with accessors getSlot1 and getSlot2. Then the following code would set up a princ type printer for MyClass

     let princMyClass(let obj, ostream& s) {
       s << "MyClass object: slot1: "
         << getSlot1(obj) << "  slot2: " << getSlot2(obj);
       return obj;}
     
     let mc1 = makeInstance(MyClass(76, "trombones"));
     
     cout << mc1 << endl; // Would produce
     
             <Lpp Testclass>
     
     setTypePrinc(type(MyClass), L(princMyClass));  // Then
     
     cout << mc1 << endl; // Would produce instead
     
             MyClass object: slot1: 76  slot2: trombones
     

The default princ and prin1 type dispatching functions for any Lpp type will print an object as

     <Lpp xxxx>
     

where xxxx will be the type name of the object. The princ type dispatching function is the one used by the princ function and also by the << operator as seen above.

setTypePrins type function Function

setTypePrins sets both the princ and prn1 printing function to the same function.

When an Lpp equality predicate of either equal or equalp is called, an equality dispatcher function of the Type meta-object is called to compute the predicate. The two arguments of the equality predicate are passed to the dispatcher function and the returned result is the result of the equality predicate. The equality dispatcher functions can be accessed with the following

setTypeEqual type function Function

getTypeEqual type Function

setTypeEqualp type function Function

getTypeEqualp type Function

The setTypeEqual function sets the equal dispatcher function of the Type meta-object type to the given function function which is an Lpp function object of two arguments. When equal is called given two objects where the first object is of this type then the function function is automatically dispatched on the object. Given both objects the function should return t if the objects are considered to be "equal" and nil otherwise. As an example suppose that we had defined an Lpp class called MyClass then

     let myClassEqual(let o1, let o2) {
           return equal(the(MyClass, o1).slot1, the(MyClass, o2).slot1);}
     
     let mc1 = makeInstance(Myclass("foo"));
     let mc2 = makeInstance(Myclass("foo"));
     
     equal(mc1, mc2) => nil
     setTypeEqual(type(Myclass), L(myClassEqual));
     equal(mc1, mc2) => t
     

setTypeEqualp does the same thing as setTypeEqual except that when equalp is called given two objects where the first object is of the type type then the function function is automatically dispatched on the object. Given both objects the function should return t if the objects are considered to be "equalp" and nil otherwise. getTypeEqual and getTypeEqualp will return the last equal, equalp dispatcher functions respectively set for the given type.

If a type meta-object does not have a equality dispatcher function set this way then eq will be used as the default.

setTypeExt type extension Function

getTypeExt type Function

The Lpp user can set up his own Type meta-object extension to any Lpp Type meta-object. He first defines an Lpp class that will be the meta-object extension class and then instantiates a object of that class which he then sets in the desired Type meta-object by calling setTypeExt on the desired Type type and meta-object extension is that newly instantiated object. getTypeExt would return the last extension set in the given type meta-object.

As an example this is useful when over some number of classes the user wants to dispatch on a common action, like the princ printing action above. Since the extension is a first class Lpp object it can be exchanged dynamically. So, for example, the user can cause a collection of classes to behave one way in one mode and then another way in a different mode. Also all Lpp objects Type meta-objects are guaranteed to have an extension even if only nil which would usually be a default case or no action.