Writing modular code with objects

Objects are more complex than was implied in the earlier sections of this document. Objects can contain both functions and data, and any of these may need to be hidden from the outside world. The design of a set of objects must take into account the visibility of each part of the code.

Let's look at an example. Suppose we have a source file called stuff.c containing the following code:


	int index = 0;

	void inc(void) { ++index; }
	void dec(void) { --index; }
	int show(void) { return index; }

	int addtwo(int a, int b) { return a+b; }
	int addthree(int a, int b, int c) { return a+b+c; }

In the first part of the file, the goal is to have index hidden from the outside and accessible only via the functions inc(), dec(), and show(). As written, when this file is compiled into an object, index will NOT be hidden from other sources. For example, we could write a source named cheat.c containing the following code:

	void main(void) { index = 100; }

and compile it with cc -o cheat cheat.c stuff.c. This program will change index to 100 without any problems. How do we prevent this?

A common misunderstanding about objects is the belief that you need an object-oriented language to hide things like index. This is not true. In C, data and functions can be declared as static, which means they are only visible within their declared scope. In the case of index, this means it is only visible to things within the file stuff.c. Each of the functions inc(), dec(), and show() have to have access to the variable index, but the other functions in stuff.c do not.

Okay, so we'll rewrite the file making index static, but before we do, note that the functions addtwo() and addthree() are not related to the other parts of the source at all. If fact, they aren't actually related to each other, so let's break stuff.c into the three files index.c:


	static int index = 0;

	void inc(void) { ++index; }
	void dec(void) { --index; }
	int show(void) { return index; }

addtwo.c:

	int addtwo(int a, int b) { return a+b; }

and addthree.c:

	int addthree(int a, int b, int c) { return a+b+c; }

Now, when we compile, we'll have three objects which are small, self-contained, and hide their internal workings from other sources. This is the goal of modularity. If we want to improve any of these pieces, we can do so without rewriting other sources; we only need to recompile them. If we choose to rewrite index.c to not use the variable index, we can do this without changing the interface to the outside world.

Speaking of interfaces, what are the interfaces that these modules present? As far as the outside world knows, index.c contains only the functions inc(), dec(), and show(). It is only inside that index is known. Each of the other two sources present just the one function they contain.

So we see that modular coding is not about what language you use, but about designing your code around small pieces with specific interfaces that can be combined to form larger pieces and applications. THIS is what modular coding is about.


This page was last modified .