7.1. Functions and Composition

So far we have focused on writing procedures - problem solving recipes that do part of a job and return no answer. Now we will shift our attention to functions - problem solving recipes that are designed to calculate some value and return it to the code that calls the function so we can do more work with the result.

In the sample below, we can see the importance of returning results from functions so that we can string together a number of steps. Line 3 calls the input function to get a string like "4" from the user and store it as sideAText. Then on line 5 we use the float function to turn that string into a numeric value 4.0 and store that in sideA. We then use math.pow to raise that value to the second power and store the result as aSquared. aSquared gets used as part of the input to the math.sqrt function which produces our final answer sideC which gets passed to the print function.

The fact that every function (other than print) returns a value is what allows to chain this work together and use the result of one function as the input to the next function. We take the returned value (the output of the function) and store it into a variable so we can pass it on to the next as input.

Note that just like with procedures, some functions like input are standalone and are called on their own. Other functions are part of a library or object and must be called with dot notation like math.pow.

7.1.1. Function Composition

We can more directly specify to use the result of calling one function as the input to another function via functional composition. That is where we put one function call inside of another - like how this version of the same program does float(input("Enter length of side A")).

Like when doing math, we always do work inside of parentheses before worrying about the work outside of them. In this case, that means we start with the "Enter length of side A". It is just a string, so there is nothing special to do with it other than use it as the argument to input(). Then the input function runs and does its job to get input from the user. It returns a string with whatever the user typed. Recall that the mental model you should use forget function calls is that they are replaced by the value they return. So input("Enter length of side A") ends up just becoming something like "4". That value is what gets used as the argument for float().

When sqrt(pow(sideA, 2) + pow(sideB, 2)) is evaluated, we have to start with the inner functions and get answers for pow(sideA, 2) and pow(sideA, 2). Then we can add those answer to get one number. That one number ends up being the argument for sqrt which takes the square root of it and returns the answer.


Writing code using functional composition in this style can make programs look shorter, but it tends to make them harder to debug. In the first version of this program, we could add a print call after any line to see what value a function produced and check if it is correct. If something isn’t working right in a line of code like sqrt( pow(sideA, 2) + pow(sideB, 2) ), it can be hard to figure out what part is not working as expected - the pow, the +, or the sqrt.

You have attempted of activities on this page