The Science of Programming/EncapsulatingOperations

=Encapsulating Sequences of Operations=

Defining Functions
Recall, the series of expressions we evaluated to find the y-value of a point on the line

$$   y = 6x - 12 $$ given an x-value:

Now, suppose we wished to find the y-value corresponding to a different x-value or, worse yet, for a different x-value on a different line. All the work we did would have to be repeated. A function is a way to encapsulate all these operations so we can repeat them with a minimum of effort.

First, we will define a not too useful function that calculates y give a slope of 6, a y-intercept of -12, and an x-value of 9 (exactly as above).

Notice that the interpreter prompt changes to when it the input is incomplete. In the case of the function definition above, that occurs when the curly close brace is entered (1).

Once the function is defined, we can find the value of y repeatedly:

This function is not too useful in that we cannot use it to compute similar things, such as the y-value for a different value of x. A hallmark of a good function is that is lets you compute more than one thing. We can modify our function to take in the value of x we are interested in. We do this by passing in an argument, in this case, the value of x.

We give names to the values being passed in by placing variable names between the function definition parentheses. In this case, we chose x as the name. Notice that since we are passing in x, we no longer need (or want) the definition of x, so we delete it. Now we can compute y for an infinite number of x's.

What if we wish to compute a y-value for a given x for a different line? One approach would be to pass in the slope and intercept as well as x:

If we wish to calculate using a different line, we just pass in the new slope and intercept along with our value of x. This certainly works as intended, but is not the best way. One problem is that we keep on having to type in the slope and intercept even if we are computing y-values on the same line. Anytime you find yourself doing the same thing over and over, be assured that someone has thought of a way to avoid that particular tedium. So assuming that is true, how do we customize our function so that we only have to enter the slope and intercept once per particular line? We will explore three different ways for doing this. In reading further, it is not important if you understand all that is going on. What is important is that you know other approaches exist and understand the pros and cons of each approach:

Creating functions on the fly
At this point, you should see that you can create functions and should be able to create other functions through pattern matching. For example, you ought to be able to define a function that squares a given number:

Since creating functions is hard work (lots of typing) and Computer Scientists avoid hard work like the plague, somebody early on got the idea of writing a function that itself creates functions! Brilliant! We can do this for our line problem. We will tell our creative function to create a findY function for a particular slope and intercept!

See how our creative function defines a findY function and then returns it. Now we can create a bunch of different findY's.

Notice how findYa and findYb remember the slope and intercept supplied when they were create. While this is decidedly cool, the problem is many languages (C and Java included) do not allow you to define functions that create other functions.

Using objects
Another approach to our line problem is to use something called an object. In Sway, an object is simply an environment and we have seen those before. So there is nothing new here except in how to use objects to achieve our goal. Here, we define a creating function (known as a constructor) that creates and returns a line object.

The this variable always points to the current environment, which, in this case, includes slope and intercept. By returning this, we return this environment, and we can look up the values of slope and intercept at our leisure. To prove that slope and intercept exist, we can use the built-in bindings function:

We access the variables in an object with the '.' (dot) operator:

Now we modify our findY function to take in a line object as well as x and use the dot operator to extract the line's slope and intercept:

In this scenario, we create different lines, then pass each line to our new findY function:

The problem with this approach is we have separated line objects from finding y values, yet these two concepts are closely related. As an example, suppose we have parabola objects as well as line objects. Our findY function would fail miserably for parabola objects even though the concept of (x,y) points on a parabola is just as valid as points on a line (2). In the object oriented world, we solve this problem by bundling the object and functions that work specifically on that object together. In our case, we make the findY function part of the line object:

This is very similar to the functions-on-the-fly approach, but we return this instead of findY. Now we call the findY function via the line object.

Should we have a parabola object, it would have its own findY function with a different implementation. We would call it just the same, however:

This approach is supported in object oriented languages such as Java. The earlier approach (where the function was separated from the object) is supported in procedural languages such as C.

Exercises
(1) Typing a long construct into the interpreter is tedious. Later we will learn how to store our code in a file and have the interpreter execute the code in that file. If we need to make changes to our code, we simply edit the file. That way, we do not need to type in the modified code into the interpreter from scratch.

(2) Here is a concrete example of trying to generalize, so that our function works for all objects for which the concept of the function is valid.