EECS20N: Signals and Systems

Declarative and imperative definitions

We have seen that one way to define function uses a predicate that declares a relationship between the domain and the range by defining the graph of the function. Equivalently, we use the pattern of the following example:

f: RealsReals, where for all tReals,

f(t) = sin(880πt).

This way of defining function is said to be declarative because it declares a relationship. It tells us "what is." An alternative way to define a function is imperative. In an imperative definition, we give a constructive way to find the element in the range that corresponds to a given element in the domain. An imperative description tells us "how to."

Consider the following mathematical equation:

y = sin(x)/x

Consider the following Matlab statement:

     y = sin(x)/x
or even an equivalent Java statement
     y = Math.sin(x)/x;
Superficially, these look very similar. There are minor syntactic differences in the Java statement, but otherwise, it is hard to tell the difference. But there are differences.
  • The mathematical equation has meaning if y is known and x is not. The mathematical equation declares a relationship between x and y. The Java and Matlab statements define a procedure for computing y given x. Those statements have no meaning if y is known and x is not.

  • These two do not define the same function. To see this, consider the value of y when x = 0. Given the mathematical equation, it is not entirely trivial to determine the value of y. You can do it using l'Hopital's rule to determine that y = 1. The meaning of the Java and Matlab statements is that y = 0/0, which Java and Matlab (and most modern languages) define to be NaN, not a number. Thus, given x = 0, the two yield different values for y.
The mathematical equation is a declarative definition of a function, which is called the Sinc function, while the Java and Matlab statements are imperative definitions of a different function, which differs from the Sinc function only at zero.

The second of these two points highlights some of the strengths and weaknesses of the two approaches. Given the mathematical equation only, it is difficult for a computer to determine the value of y. Symbolic mathematical software, such as Maple and Mathematica, is designed to deal with such situations, but these are very sophisticated programs. In general, using declarative definitions in computers requires quite a bit more sophistication than using imperative definitions. But declarative definitions are relatively easy for humans to work with.

Imperative definitions are easier for computers to work with. But the Java and Matlab statements illustrate one weakness of the imperative approach: it is arguable that y = NaN is the wrong answer, so the Java and Matlab statements have a bug. This bug is unlikely to be detected unless, in testing, these statements happens to be executed with the value x = 0. A correct Matlab program might look like this:

     if (x == 0.0) y = 1.0;
     else y = sin(x)/x;
Formally, the declarative approach establishes a relation between the domain and the range of a function. In the above example, the domain and the range, the possible values of x and y, are both the set Reals. The equation
     y = sin(x)/x
can be viewed as defining a subset of Reals × Reals. Recall that this subset is the graph of the function Sinc: RealsReals.

Formally, the imperative approach also establishes a relation, but it is a relation between the program state before and after the statement is executed. In the above example, for both Java and Matlab, the program state is the value of the two variables, x and y. The set of possible program states is therefore Doubles × Doubles, where Doubles is the set of double-precision floating point numbers (including NaN). Thus, the Matlab statement

     y = sin(x)/x
defines a relation that is a subset of (Doubles × Doubles) × (Doubles × Doubles). This subset is the graph of the function:

Statement: (Doubles × Doubles) → (Doubles × Doubles).