\chapter{Fruitful functions}
\label{lecture-fruity}

\section{The return statement}

The return statement allows you to terminate the execution of a
function before you reach the end. One reason to use it is if you
detect an error condition:
% Why x<=0 rather than x<0? 
\begin{python}
def print_square_root(x):
    if x < 0:
        print "Warning: cannot take square root of a negative number."
        return

    result = x**0.5
    print "The square root of x is", result
\end{python}

The function \pythoninline{print\_square\_root} has a parameter named
\pythoninline{x}. The first thing it does is check whether
\pythoninline{x} is less than \pythoninline{0}, in which
case it displays an error message and then uses \pythoninline{return}
to exit the 
function. The flow of execution immediately returns to the caller, and
the remaining lines of the function are not executed. 

\section{Return values}

The built-in functions we have used, such as \pythoninline{abs},
\pythoninline{pow}, and \pythoninline{max}, have 
produced results. Calling each of these functions generates a value,
which we usually assign to a variable or use as part of an expression.
\begin{python}
biggest = max(3, 7, 2, 5)
x = abs(3 - 11) + 10
\end{python}

But so far, none of the functions we have written has returned a
value. In this lecture, we are going to write functions that return values,
which we will call \myidx{fruitful functions}, for want of a better
name. The first example is \pythoninline{area\_of\_circle}, which returns the area
of a circle with the given radius:

\noindent
\begin{minipage}{\textwidth}
\begin{python}
def area_of_circle(radius):
    if radius < 0:
        print "Warning: radius must be non-negative"
        return

    temp = 3.14159 * radius**2
    return temp
\end{python}
\end{minipage}

We have seen the \pythoninline{return} statement before, but in a
fruitful function the \pythoninline{return} statement includes a
\myidx{return value}. This statement means: Return immediately from
this function and use the following expression as a return value. The
expression provided can be arbitrarily complicated, so we could have
written this function more concisely: 
\begin{python}
def area_of_circle(radius):
    if radius < 0:
        print "Warning: radius must be non-negative"
        return

    return 3.14159 * radius**2
\end{python}
On the other hand, \myidx{temporary variables} like temp often make
debugging easier. Sometimes it is useful to have multiple \pythoninline{return}
statements, one in each branch of a conditional. We have already seen
the built-in \pythoninline{abs}, now we see how to write our own:
\begin{python}
def absolute_value(x):
    if x < 0:
        return -x
    else:
        return x
\end{python}

Since these \pythoninline{return} statements are in an alternative
conditional, only 
one will be executed. As soon as one is executed, the function
terminates without executing any subsequent statements.
Another way to write the above function is to leave out the
\pythoninline{else} and 
just follow the \pythoninline{if} condition by the second
\pythoninline{return} statement. 
\begin{python}
def absolute_value(x):
    if x < 0:
        return -x
    return x
\end{python}

Think about this version and convince yourself it works the same as
the first one. Code that appears 
any 
place the flow of execution can never reach, is called
\myidx{dead code}. In a fruitful function, it is a good idea to
ensure that every possible path through the program hits a
\pythoninline{return} 
statement. The following version of \pythoninline{absolute\_value}
fails to do this: 
\begin{python}
def absolute_value(x):
    if x < 0:
        return -x
    elif x > 0:
        return x
\end{python}

This version is not correct because if \pythoninline{x} happens to be
\pythoninline{0}, neither 
condition is true, and the function ends without hitting a
\pythoninline{return} 
statement. In this case, the return value is a special value called
\myidx{None}:
\begin{pythonInteractive}
>>> print absolute_value(0)
None
\end{pythonInteractive}

\pythoninline{None} is the unique value of a type called the
\pythoninline{NoneType}: 
\begin{pythonInteractive}
>>> type(None)
<type 'NoneType'>
\end{pythonInteractive}

All Python functions return \pythoninline{None} whenever they do not
return another value. 

\section{Program development}
\label{sec-program-devel}

At this point, you should be able to look at complete functions and
tell what they do. Also, while completing the laboratory exercises
given so far, you will have written some small functions. As you write
larger functions, you might start to have more difficulty, especially
with runtime and semantic errors. To deal with increasingly complex
programs, we are going to suggest a technique called
\myidx{incremental development}.  The goal of incremental development
is to avoid long debugging sessions by adding and testing only a small
amount of code at a time.

As an example, suppose you want to find the distance between two
points, given by the coordinates $(x_1, y_1)$ and $(x_2, y_2)$. By the
Pythagorean theorem, the distance is:
\begin{displaymath}
\mbox{distance} = \sqrt{(x_2-x_1)^2+(y_2-y_1)^2}
\end{displaymath}
The first step is to consider what a distance function should look
like in Python. In other words, what are the inputs (parameters) and
what is the output (return value)? In this case, the two points are
the inputs, which we can represent using four parameters. The return
value is the distance, which is a floating-point value.
Already we can write an outline of the function:
\begin{python}
def distance(x1, y1, x2, y2):
    return 0.0
\end{python}

Obviously, this version of the function doesn't compute distances; it
always returns zero. But it is syntactically correct, and it will run,
which means that we can test it before we make it more complicated.

To test the new function, we call it with sample values:
\begin{pythonInteractive}
>>> distance(1, 2, 4, 6)
0.0
\end{pythonInteractive}

We chose these values so that the horizontal distance equals 3 and the
vertical distance equals 4; that way, the result is 5 (the hypotenuse
of a 3-4-5 triangle). When testing a function, it is useful to know
the right answer.
At this point we have confirmed that the function is syntactically
correct, and we can start adding lines of code. After each incremental
change, we test the function again. If an error occurs at any point,
we know where it must be---in the last line we added.

A logical first step in the computation is to find the differences $x_2
- x_1$ and $y_2 - y_1$. We will store those values in temporary variables
named \pythoninline{dx} and \pythoninline{dy} and print them.

\noindent
\begin{minipage}{\textwidth}
\begin{python}
def distance(x1, y1, x2, y2):
    dx = x2 - x1
    dy = y2 - y1
    print "dx is", dx
    print "dy is", dy
    return 0.0
\end{python}
\end{minipage}

If the function is working, the outputs should be 3 and 4. If so, we
know that the function is getting the right parameters and performing
the first computation correctly. If not, there are only a few lines to
check.

Next we compute the sum of squares of dx and dy:
\begin{python}
def distance(x1, y1, x2, y2):
    dx = x2 - x1
    dy = y2 - y1
    dsquared = dx**2 + dy**2
    print "dsquared is: ", dsquared
    return 0.0
\end{python}
Notice that we removed the print statements we wrote in the previous
step. Code like that is called \myidx{scaffolding} because it is
helpful for building the program but is not part of the final product.
Again, we would run the program at this stage and check the output
(which should be 25).
Finally, using the fractional exponent 0.5 to find the square root, we
compute and return the result:
\begin{python}
def distance(x1, y1, x2, y2):
    dx = x2 - x1
    dy = y2 - y1
    dsquared = dx**2 + dy**2
    result = dsquared**0.5
    return result
\end{python}

If that works correctly, you are done. Otherwise, you might want to
print the value of result before the return statement.
When you start out, you should add only a line or two of code at a
time. As you gain more experience, you might find yourself writing and
debugging bigger chunks. Either way, the incremental development
process can save you a lot of debugging time.

The key aspects of the process are:
\begin{enumerate}
\item Start with a working program and make small incremental
  changes. At any point, if there is an error, you will know exactly
  where it is.
\item Use temporary variables to hold intermediate values so you can
  output and check them.
\item Once the program is working, you might want to remove some of
  the scaffolding or consolidate multiple statements into compound
  expressions, but only if it does not make the program difficult to
  read.
\end{enumerate}
\section{Composition}

As you should expect by now, you can call one function from within
another. This ability is called \myidx{composition}. As an example,
we'll write a function that takes two points, the center of the circle
and a point on the perimeter, and computes the area of the circle. 
Assume that the center point is stored in the variables
\pythoninline{xc} and \pythoninline{yc}, and the perimeter point is in
\pythoninline{xp} and \pythoninline{yp}. The first step is to find the
radius of the circle, which is the distance between the two points. 
Fortunately, we've just written a function, distance, that does just
that, so now all we have to do is use it:
\begin{python}
radius = distance(xc, yc, xp, yp)
\end{python}
The second step is to find the area of a circle with that radius and
return it. Again we will use one of our earlier functions:
\begin{python}
result = area_of_circle(radius)
\end{python}

Wrapping that up in a function, we get:
\begin{python}
def area_of_circle_two_points(xc, yc, xp, yp):
    radius = distance(xc, yc, xp, yp)
    result = area_of_circle(radius)
    return result
\end{python}


We called this function \pythoninline{area\_of\_circle\_two\_points}
to distinguish it from the 
\pythoninline{area\_of\_circle} function defined earlier. There can only be one
function with a 
given name within a given module. The temporary variables radius and
result are useful for development and debugging, but once the program
is working, we can make it more concise by composing the function
calls:
\begin{python}
def area_of_circle_two_points(xc, yc, xp, yp):
    return area_of_circle(distance(xc, yc, xp, yp))
\end{python}

\section{Boolean functions}

Functions can return boolean values, which is often convenient for
hiding complicated tests inside functions. For example:
\begin{python}
def is_divisible(x, y):
    if x % y == 0:
        return True 
    else:
        return False
\end{python}

The name of this function is \pythoninline{is\_divisible}. It is common to give
\myidx{boolean functions} names that sound like yes/no
questions. \pythoninline{is\_divisible} returns either
\pythoninline{True} or \pythoninline{False} to indicate whether the
\pythoninline{x} is or is not divisible by \pythoninline{y}.
We can make the function more concise by taking advantage of the fact
that the condition of the \pythoninline{if} statement is itself a boolean
expression. We can return it directly, avoiding the \pythoninline{if} statement
altogether:
\begin{python}
def is_divisible(x, y):
    return x % y == 0
\end{python}

This session shows the new function in action:
\begin{pythonInteractive}
>>> is_divisible(6, 4)
False
>>> is_divisible(6, 3)
True
\end{pythonInteractive}

Boolean functions are often used in conditional statements:
\begin{python}
if is_divisible(x, y):
    print "x is divisible by y"
else:
    print "x is not divisible by y"
\end{python}
It might be tempting to write something like:
\begin{python}
if is_divisible(x, y) == True:
    print "x is divisible by y"
else:
    print "x is not divisible by y"
\end{python}
But the extra comparison is unnecessary.

\section{The function type}
A function is another type in Python, joining int, float, str, bool,
and \pythoninline{NoneType}.
\begin{pythonInteractive}
>>> def func():
...    return "function func was called..."
...
>>> type(func)
<type 'function'>
>>>
\end{pythonInteractive}

Just like the other types, functions can be passed as arguments to
other functions:
\begin{python}
def f(n):
    return 3*n - 6

def g(n):
    return 5*n + 2

def h(n):
    return -2*n + 17

def doto(value, func):
    return func(value)
    
print doto(7, f)
print doto(7, g)
print doto(7, h)
\end{python}

\pythoninline{doto} is called three times. 7 is the argument for value
each time, and the functions \pythoninline{f}, \pythoninline{g}, and
\pythoninline{h} are passed in for \pythoninline{func} in turn. The
output of this script is:
\begin{pythonOutput}
15
37
3
\end{pythonOutput}

This example is a bit contrived, but we will see situations later
where it is quite useful to pass a function to a function.

\section{Glossary}
\begin{description}
\item[fruitful function:]A function that yields a return value.
\item[return value:]The value provided as the result of a function
  call.
\item[temporary variable:]A variable used to store an intermediate
  value in a complex calculation.
\item[dead code:]Part of a program that can never be executed, often
  because it appears after a return statement.
\item[\pythoninline{None}:]A special Python value returned by functions that have no
  return statement, or a return statement without an argument. \pythoninline{None} is
  the only value of the type, \pythoninline{NoneType}.
\item[incremental development:]A program development plan intended to
  simplify debugging by adding and testing only a small amount of code at
  a time.
\item[scaffolding:]Code that is used during program development but is
  not part of the final version.
\item[boolean function:]A function that returns a boolean value.
\item[composition (of functions):]Calling one function from within the
  body of another, or using the return value of one function as an
  argument to the call of another.
\end{description}

\newpage
\section{Laboratory exercises}

\begin{enumerate}
\item Write a function called \pythoninline{is\_even(n)} that takes an
integer as an 
argument and returns True if the argument is an \myidx{even number}
and False if it is \myidx{odd} . 

\item Now write the function \pythoninline{is\_odd(n)} that returns
 \pythoninline{True} when  \pythoninline{n} is odd and \pythoninline{False}
otherwise. Finally, modify it so that it uses a call to
\pythoninline{is\_even} to determine if its argument is an odd integer.

\item Write a function called \pythoninline{is\_factor} which returns
\pythoninline{True} if the first argument is a factor of the second.
That is, \pythoninline{is\_factor(3, 12)} is \pythoninline{True}
whereas \pythoninline{is\_factor(5, 12)} is \pythoninline{False}.

\item Write a function called \pythoninline{hypotenuse} that returns
the length of the hypotenuse of a right angled triangle given the
length of the other 
two sides as parameters. Here's an initial definition:
\begin{python}
def hypotenuse(a,b):
    return 0.0
\end{python}

\item \emph{Extension Exercise:} Recall that the equation for a line
can be written as $y = m x + c$, where $m$ is the slope of the line
and $c$ is the $y$-intercept. For a line that passes through two
points, $(x_1, y_1)$ and $(x_2, y_2)$, we have the following
identities:
\begin{eqnarray*}
m &=& \frac{y_2-y_1}{x_2-x_1} \\
c &=& y_1 - m x_1 \\
\end{eqnarray*}
\begin{enumerate}
\item Write a function \pythoninline{slope(x1, y1, x2, y2)} that
returns the slope of the line through the points \pythoninline{(x1,
y1)} and \pythoninline{(x2, y2)}. 
\item Write a function \pythoninline{intercept(x1,~y1,~x2,~y2)} that
returns the $y$-intercept
of the line through the points \pythoninline{(x1,~y1)} and
\pythoninline{(x2,~y2)}.
\end{enumerate}

\item If you didn't complete all the levels of the game in the
  previous lab try to finish it this time.

\end{enumerate}

\submitreminder
