A powerful programming language is more than just a means for instructing a computer to perform tasks. The language also serves as a framework within which we organize our ideas about processes. Thus, when we describe a language, we should pay particular attention to the means that the language provides for combining simple ideas to form more complex ideas. Every powerful language has three mechanisms for accomplishing this:
In programming, we deal with two kinds of elements:
procedures
functions
and
data. (Later we will discover that they are really not so distinct.)
Informally, data is stuff
that we want to manipulate, and
procedures
functions
are descriptions of the rules for manipulating the data.
Thus, any powerful programming language should be able to describe
primitive data and primitive
procedures
functions
and should have methods for
combining and abstracting
procedures
functions
and data.
In this chapter we will deal only with simple numerical data so that we can focus on the rules for building proceduresfunctions.[1] In later chapters we will see that these same rules allow us to build procedures functions to manipulate compound data as well.
simple datais a barefaced bluff. In fact, the treatment of numbers is one of the trickiest and most confusing aspects of any programming language. Some typical issues involved are these: Some computer systems distinguish integers, such as 2, from real numbers, such as 2.71. Is the real number 2.00 different from the integer 2? Are the arithmetic operations used for integers the same as the operations used for real numbers? Does 6 divided by 2 produce 3, or 3.0? How large a number can we represent? How many decimal places of accuracy can we represent? Is the range of integers the same as the range of real numbers? Above and beyond these questions, of course, lies a collection of issues concerning roundoff and truncation errors—the entire science of numerical analysis. Since our focus in this book is on large-scale program design rather than on numerical techniques, we are going to ignore these problems. The numerical examples in this chapter will exhibit the usual roundoff behavior that one observes when using arithmetic operations that preserve a limited number of decimal places of accuracy in noninteger operations.