Sifting through Layers of C

Libraries of functions serve a vital role in the development of software. In particular, when we organize a large project, one of the most helpful concepts is layering.

Let us illustrate layering by way of an example. Suppose that we're developing a program that analyzes and manipulates pyramids. For such a program we'll need several parts. Among them will be some functions that operate on triangles and these functions will in turn likely depend on the math library discussed in Part 2-6. We'll also need some code that maintains our database of pyramids (from Giza to Memphis). This part will likely depend on the standard I/O library. We can depict the relationship among these parts as in the following diagram:

|          Main Program           |
|   Triangle    |     Database    |
|   Support     |     Support     |
|    Math       |   Standard I/O  |
|   Library     |     Library     |
|        Operating System         |
|            Hardware             |

There a a couple of ideas here that are important for us. First, this diagram illustrates the layering principle which we state as follows:

No function in a lower layer shall call a function contained in a higher layer.
(There is a mechanism for dealing with cases where we need to call upwards. We pass the upper layer function as an argument to the lower layer function that will call it.)

The second concept we want to see in this diagram is that of the virtual machine. Here the idea is that if we view the collection of code below some layer, we can't see and don't really care what the exact details are in those lower layers. The only thing we need to know is what functions are defined for the virtual machine that we're coding on. Another way to look at this is that we can't tell if we're running our program on a computer with very simplistic hardware combined with sophisticated supporting software or on a feature-laden computer with need for little support software.

Another Example

A little later in the semester we'll take a look at part of a real-world software project. (We'll only look at a part of it since the whole thing is about 18,000 lines of code.) This system is also designed in layers as illustrated in this diagram:
|  |  |  |  |  |   About 40     |  |
|  |  |  |  |  |  Individual    |  |
|  |  |  |  |  |  Application   |  |
|  |  |  |  |  |   Programs     |  |
|      Application Specific        |
|            Library               |
|                |   Windowing     |
|   Record I/O   |    Library      |
|    Library     +-----------------+
|                |    Curses       |
|                |    Library      |
|       Standard Library/          |
|       Operating System/          |
|           Hardware               |
|            (POSIX)               |
In this diagram, we take advantage of the virtual machine concept and lump the resources provided to us before we design the program together in the lowest layer. We label them POSIX which is the name of a standard set of function calls that are defined to provide a portable programming interface. In other words, software written to use only POSIX calls can be expected to run on a wide variety of computers. The other libraries that are used in the design above each serve a particular purpose:
  1. Application Specific Library - This library is mainly one of convenience. It holds a number of functions that are used through many of the application programs. These functions are grouped here so that we don't need to repeat them in each of the applications that uses them.
  2. Record I/O Library - This library serves the same purpose as the database support library in the previous example. It provides a number of database handling services that can be used in a number of different application domains.
  3. Windowing Library - This library defines the user interface component of the system. This is where we define things like menus, forms, message boxes and reports that may go to the screen or to the printer.
  4. Curses Library - Curses is a package originally developed at Berkeley to provide terminal independent support for the placement of text on the screen.

The sub-field of computer science known as software engineering focuses (among other things) on techniques for structuring large programs. While the examples we've looked at hardly count as large systems (large systems are usually thought of as 100,000 or 1,000,000 lines of code), the layering technique is one of the most fundamental techniques for structuring software.

Click here to go on to the next part.