|
Summary
Classes in object oriented systems have been with us for many years now. We have learned to use these to encapsulate the data and functionality of entities and processes in our business logic. We have also learned how to use inheritance to derive the basic functionality we need and build upon that as a form of code reuse. However, in larger applications we have also seen the downside: building class hierarchies whose value crumbles under their own weight. Too many classes which do too much, being carried around by objects all the time. Yet with all this functionality, most of it goes unused most of the time (if I may hazard a guess, 80% of the time). Wouldn't it be nice if there was a way in which an object could pick and choose the services it needed, when it needed them and then discard them when done? This is what object reclassification is all about.
The Point of Relevance
There is a school of thought in programming that says that you should declare your variables at the point when you need them and not far off (i.e. not at the top of the function or program). The general idea behind this is that the code and its associated variables should be contained together. This way they are easier to find and maintain. There is another reason as well, since the variables are defined right at the point when they are needed they are not needlessly carried around by the program. This saves memory (which may or may not be an issue, depending on what you are doing). For us, the point to observe is that we can consider the variables and the data they contain as offering some kind of service to the code at that location. Since they are not used by the rest of the program, there is no need for them to be declared at the top of the program. Rather than declare them far away, it is better to declare them right near the point of use. This is the point when the variables become relevant. Anywhere else and they are meaningless.
When you declare classes and create an instance that inherits from these classes, you are doing something similar to the variable declaration we have discussed above. You are saying that here is a set of services that are to be used by the instance. Now, if you do not use these services most of the time then you are carrying around extra and unnecessary weight. In the case of memory consumption, this is even more wanton than the declaration of variables since the classes are much larger structures in memory than simple variables. The other issue of consideration is that the classes are really meaningless until the point when their members and methods are used. They lack relevance except when they are invoked. It is then that their existence is valuable to the object.
Lessons in Multiple Inheritance
Multiple inheritance taught us that we can gather different sets of functionality (or services) for the use of a single instance. For instance, let us consider the case of an engineering company. We have managers and we have engineers. However, not all managers are engineers but some are. In this scenario, we can consider an individual (the instance) who is both a manager (instance inherits from Manager class) and an engineer (instance inherits from Engineer class). The code snippet below shows the two classes and the created instance.
<!-- the Manager class -->
<class name=Manager>
<scope type=public>
<func type=void name=CalculateBonus>
<body>
<!-- calculate the manager's bonus here -->
</body>
</func>
.
.{other members and methods}
.
</scope>
</class>
<!-- the Engineer class -->
<class name=Engineer>
<scope type=public>
<func type=void name=CalculateRaise>
<parm type=int name=iYearlyPercentageIncrease />
<body>
<!-- calculate the engineer's raise here -->
</body>
</func>
.
.{other members and methods}
.
</scope>
</class>
<!-- MyEngineer is an instance of both Manager and Engineer -->
<node name=MyEngineer class=Manager,Engineer />
|
We can call the methods and access the members of both the Manager and Engineer classes in the MyEngineer object. This is all very nice in our little example, but when the number of methods increases in the classes and we only use some of the methods and members for a minority of the time then we are in problems. We will have a large overhead caused by the multiple inheritance. How can we find a way to only carry the bare minimum of what the MyEngineer object needs all of the time, and only get the extra stuff whenever we need it? This can be done using object reclassification.
Be What You Want, When You Want
The object reclassification feature of Superx++ enables an object to be an instance of a class in one moment and then change to be the instance of another class in the next. This is all a case of being what it wants, when it wants (or needs) to be. So if, in the example above, there are many methods attendant with the Manager class, yet the MyEngineer object spends most of its time doing actual engineering, then we should do the following:
| 1) |
Make the Engineer class the primary class of the MyEngineer object |
| 2) |
Add in the Manager class functionality only when MyEngineer needs to do some managerial work. This will be in a minority percentage of the time because the MyEngineer does more engineering than managing. |
How do we make the Engineer class the primary class of the MyEngineer object? We do this as follows:
<!-- MyEngineer is an instance of Engineer -->
<node name=MyEngineer class=Engineer />
|
Notice that the only class that MyEngineer is said to inherit from is the Engineer class. At this point, the only methods and members being carried around by the MyEngineer object are those of the Engineer class. Since these are the members and methods that will be used most of the time by the MyEngineer object, since he spends most of his time doing actual engineering work, this is not a problem.
What do we now do about getting the Manager class functionality when we need it? You add in the Manager class functionality by switching the class attribute of the MyEngineer object. This is done in the line below:
<eval object=MyEngineer attribute=class>Manager</eval>
|
At this point, what we have done is change the MyEngineer object from being an instance of the Engineer class to being an instance of the Manager class. We can now call the methods and access the members of the Manager class freely. Once we are done with invoking the methods and members of the Manager class (i.e. we are done using the services of the Manager class) we should change the MyEngineer object back into an instance of the Engineer class. This is done in a line very similar to the one used above:
<eval object=MyEngineer attribute=class>Engineer</eval>
|
From this point on, the MyEngineer object is an instance of the Engineer class, just the same way it was when we first created it.
The Complete Program
The following is the new program that uses the object reclassification feature to add the Manager class service at the point of relevance.
<?xml version=1.0 encoding=utf-8 ?>
<xpp xmlns=http://www.superxlang.org/NS>
<!-- the Manager class -->
<class name=Manager>
<scope type=public>
<func type=void name=CalculateBonus>
<body>
<!-- calculate the manager's bonus here -->
</body>
</func>
.
.{other members and methods}
.
</scope>
</class>
<!-- the Engineer class -->
<class name=Engineer>
<scope type=public>
<func type=void name=CalculateRaise>
<parm type=int name=iYearlyPercentageIncrease />
<body>
<!-- calculate the engineer's raise here -->
</body>
</func>
.
.{other members and methods}
.
</scope>
</class>
<!-- MyEngineer is an instance of the Engineer class -->
<node name=MyEngineer class=Engineer />
<!-- at this point we can invoke the methods and members of the Engineer class
e.g. Let us give MyEngineer a 5% raise -->
<eval object=MyEngineer method=CalculateRaise>
<parm type=int>5</parm>
</eval>
<!-- We can continue invoking the methods and members of the Engineer class
for MyEngineer at this point -->
<!-- at some point we need to do some computations related to the Manager
class on MyEngineer so let us reclassify MyEngineer to being an instance
of the Manager class -->
<eval object=MyEngineer attribute=class>Manager</eval>
<!-- at this point we can invoke the methods and members of the Manager class
e.g. Let us give MyEngineer a bonus -->
<eval object=MyEngineer method=CalculateBonus />
<!-- We can continue invoking the methods and members of the Manager class
for MyEngineer at this point -->
<!-- Now that we are done with the computations related to the Manager class
on MyEngineer let us reclassify MyEngineer back to being an instance
of the Engineer class -->
<eval object=MyEngineer attribute=class>Engineer</eval>
<!-- From here on out, MyEngineer is back to being an instance of the Engineer class, so we can
invoke the methods and members of the Engineer class on MyEngineer as normal. -->
</xpp>
|
Moral of the Story...
The benefits of object reclassification are:
Reducing overhead from extra classes
Classes are very useful for encapsulating the services they offer to objects. However, they represent significant overhead when they are not used. Since their lack of use exceeds their use, most classes can be left out of the initial instantiation of the object. Instead they can be brought in to serve their purpose at the point of relevance, i.e. when they are needed. Then once they are no longer used they can be discarded. All this is possible using object reclassification.
Better understanding of the code
Object reclassification makes for a better understanding of what the object is doing, when it is doing it, since you reclassify the object at the point of relevance only. So the section of code which invokes the extra set of services is preceded by the reclassification instruction. This makes it clear to whoever is reading the source code that the extra services are being used for that section only. And if that person is reading the source code anywhere else, they need not worry about which class(es) implement the methods and members being invoked by the object in the other locations. They will definitely be those declared when the object was originally instantiated. In short, all extra method and member invocations occur just after the object reclassification; everything else is normal.
More Information?
The preceding has been a brief introduction to the topic of object reclassification. For more information on this and other topics about Superx++ you can go to the Emergent Logic web site at http://www.emergentlogic.com. If you have any questions or comments for the author of this article please e-mail me at matikm@emergentlogic.com.
Thanks,
Kimanzi Mati
Emergent Logic LLC
Updating comments...
Updating comments...
|
|
|
|
|
|