Sunday, July 25, 2010

Polymorphism: A Place in Systems Engineering?



This article originally appeared in the Fall 2009 edition of MIT SDM Pulse newsletter.

Polymorphism: A Place in Systems Engineering?

As a software architect and a systems engineer, I’ve been working with larger systems that include software, hardware, and mechanical subsystems. I work on designing software and systems for a multifunction device that scans, prints, and faxes documents. In my work, I often try to translate principles of software design to larger systems.

Once such principle is polymorphism. How does polymorphism work in systems engineering? A key principle in software engineering is that software objects should have only one function; polymorphism allows for abstract software objects to have more than one function (more on the meaning of abstract below). In the non-software world, some objects-that-you –can-hold-in-your-hands can also have more than one function. System engineers often want to fit many functions into a single piece of hardware and polymorphism is a pattern embraced by system designers.

So what the heck is polymorphism? If you are not a software engineer, you may not be familiar with the term but you are probably familiar with the principle. The basic idea is from a Greek root meaning “having multiple forms”. In object-oriented programming, polymorphism is the ability to execute a function specific to a context. The classic text-book example is with shape objects. A Shape is a general object and a Circle and Rectangle are more specific objects that inherit from a Shape. A Circle is a Shape and a Rectangle is a Shape.

In C++ here is a partial definition of a Shape object. The “virtual” function that is set to “0” means this class is an Abstract Base Class or an ABC. This object can never be instantiated or created in executable code but exists for other objects to inherit from.

class Shape {

public:

Shape();

virtual void draw()=0;

};

Now let’s define a rectangle and a circle class. These objects inherit from the Shape class. Inheritance is an “is a” relationship. That is, a Rectangle “is a” Shape and a Circle “is a” Shape.

class Rectangle: public Shape {
 
public:
   Rectangle(int width, int height);
   void draw();
 
private:
   int width;
   int height;
};

class Circle: public Shape {
 
public:
   Circle(int radius);
   void draw();
 
private:
   int radius;
};

The Rectangle and the Circle object would have their own implementations or code for the draw function. Each shape has its own formula or algorithm for drawing their shapes.

So why is this useful? In a program, the Shape object can be used to draw any shape without knowing what exact shape it is at compile time. For example, the line of code

Shape->draw() 
 

will draw correctly (with some help from the compiler). This is why C++ is a polymorphic language. You don’t need to write this kind of code:

if (Circle) then

draw a circle

else if (Rectangle) then

draw a rectangle

So this is useful with software – less code and it is easier to understand the abstraction. How is this useful in larger systems? Polymorphism can work with a vehicle that can fly, drive over roads, and float in the water. Imagine that you the driver, could drive this vehicle in the same way without know how the vehicle when over these different mediums. You just knew how to drive and it worked the same way no matter where you were. That’s polymorphism and that’s useful to the customers of my product – which is the machine that has multiple functions.

Another example of polymorphism is from my days at MIT in the SDM program. In systems engineering one day, we talked about a seat cushion in a boat. This seat cushion serves as two functions – as padding for a seat in one context and as a floatation safety device in another (this cushion has straps on it). The design of this seat cushion has been influenced by the fact that it has two functions. However it’s basic core function or Abstract Base Class is to lift a human – whether it be on a seat or in the water.

Here’s an example of how polymorphism can save Unit Manufacturing Cost (UMC). Let’s return the vehicle example. If you want a vehicle that drivers over land and floats in water you could buy two vehicles, one that runs over land and another that floats and moves in water. Or us engineers could design you one vehicle that does both. [i]

The multipurpose vehicle is more expensive than a single purpose vehicle and should be less expensive than two vehicles (one for land, one for water). That is the challenge with polymorphism. If our customers did indeed want a multi-function device and if we could reuse systems to perform multiple functions in a cost effective manner, then polymorphism works for our business.

Polymorphism has a role in product platform design. For example, a platform has a set of common functionality. How that functionality is implemented will vary on what system the platform is implemented on. Another example from my Product Design and Development class is a power tool which had a product platform of a power supply. This power supply fit onto a variety of power tools and could be switched between power tools. Like the shape and the draw function, the basic functionality of obtaining power to do work is the “base class”. The function of doing the work varies from power tool to power tool.

But polymorphism isn’t always the best idea. In product design, designing hardware to have multiple functions often has tradeoffs. For example, if you had to design a seat cushion that did not have to be flotation device, you would not be as constrained as when you had to design it as two things. Here’s where software and hardware design differs. Notice in the shape example, the Shape is a distinct object and the Circle and Square objects are distinct. Each one serves a purpose. There is no tradeoffs with polymorphism as far as the function of the object goes (there is memory cost). The Shape object is never actually created in software, but used as an abstract reference. During run time of the code, the shape object will actually always be either a Circle or a Square. Each object is distinct with only one purpose. With objects-you-can-hold, the object is two things at once. For example, the seat cushion is something that provides padding and floats a person in water. The tradeoffs are in the physical object, where in software, there is no tradeoff in the objects themselves.

Polymorphism does have an expense associated with it and should be used only when you need different functions in different contexts. The base functionality should be the same in both contexts – to draw a Shape, to drive a vehicle, to life up a person, to power a tool for work. Polymorphism is a powerful design pattern, popular is software, that can be used in larger systems to build in flexibility in product design and one that will be increasingly used in our design push to build smaller, cheaper, better products for our customers.


[i] Incidentally, such a vehicle was designed and built during WWII and many of them are still in use today with Boston Duck Tours: http://www.bostonducktours.com/duck_history_main.html