Our encapsulated world: Part 1

This begins a series of posts about a concept I find fascinating. I plan to write on this topic in the form of a series because, frankly, I can’t imagine covering all the ground I want to cover in one post. I have too little free time these days to write epic blog posts very often anymore, sadly. Maybe that’s a good thing, though, because I have so much on my mind about this subject that it could probably get pretty overwhelming if I crammed it all into one post. Hopefully I don’t put anyone to sleep.

What I want to write about is, in a word, encapsulation.

“Encapsulation” is a term software engineers use all the time. We use it to describe cases where a complex (or at least non-trivial) set of software components is “encapsulated” within a single component, allowing developers to use that component in a flexible, reusable way without always having to juggle around its constituent parts individually. Outside the world of software, it can have more or less the same meaning. Whenever you hear of “encapsulation,” the idea being described is that of taking a system of parts and conceptualizing it as a discrete unit, which makes it easier to interact with in a comprehensible way.


Some great examples exist in the realm of data structures. Generally, low-level programming languages (such as C) do not offer out-of-the-box components for representing the concept of collections of objects. At best, they provide a single, highly primitive construct: an array, or possibly even just a pointer (a location in memory), which can be used along with a length to denote a contiguous block of memory. This block can then in turn be used to store several pieces of like data (e.g., numbers or dates).

Using such constructs is tedious at best, hazardous at worst. Programmers have to worry about off-by-one errors, buffer overflows, dynamic allocation/deallocation of memory, and all kinds of other nightmarish things. But this isn’t even the important point. The important point is that you can do very little useful work with this very basic concept, without having to write thousands of lines of laborious code. Suppose you want to store data in something resembling a table, allowing lookups by unique key? What if you want to maintain a queue of items, to be processed in the order they are received? Or what about some sort of branching hierarchical structure? Good luck without encapsulation.

On the other hand, with encapsulation, it quickly becomes amazingly simple to do things that would otherwise seem impossible. If I give you an array and I say, “Now I want to insert an item in the middle of this array,” you have a frustratingly difficult task ahead of you.

Disclaimer: the code below is horrible. I refuse to claim otherwise!

template<typename T>
int insert_element(T** array, int length, int capacity, int index, T element)
{
	// Determine the location of the last element in the array.
	int lastPos = length - 1;

	// Check if the array contains as many elements as it can hold.
	if (lastPos == capacity - 1)
	{
		// Store a pointer to the old array for deallocation.
		T* temp = *array;

		// Allocate extra space for the incoming element.
		capacity *= 2;
		*array = new T[capacity];

		// Copy all the elements over from the old array.
		for (int i = 0; i < length; ++i)
		{
			(*array)[i] = temp[i];
		}

		// Deallocate the old array.
		delete [] temp;
	}

	// Shift every element over by one down to the insertion point.
	int insertionPos = index;
	for (int i = lastPos; i >= insertionPos; --i)
	{
		// Ugh... so much work!
		(*array)[i + 1] = (*array)[i];
	}

	// Insert the element.
	(*array)[index] = element;

	// Return the new capacity.
	return capacity;
}

Pretty gross, right? Now let’s try and perform the exact same task, this time with a very useful encapsulation of the above logic which performs pretty much exactly the same work while requiring a developer to write far less code: the std::vector<T> class.

template<typename T>
void insert_element(vector<T>* array, int index, T element)
{
	array->insert(array->begin() + index, element);
}

Hmm, 40 lines became 5 lines. How is that possible? Quite simply, that entire mess of code up top, comprising an array, a length, a capacity, etc., is all essentially wrapped or encapsulated—this concept goes by many names—inside the insert operation, which is just one of many operations supported by the std::vector<T> class.

So that’s one way of interpreting the word “encapsulation”: as a way of representing a detailed interdependent system of many parts as if it were a single entity.

There are many more layers of meaning to this word, which I intend to explore in future posts. At the moment I have run out of steam; but in the meantime, how many examples of encapsulation can you think of in everyday life? I honestly believe that the more you think about it, the more astounded you will become by how ubiquitous it really is.

Anyway, I’ve got plenty more to share over the coming days. Don’t you worry!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: