- how can we use functions to build abstractions?
- what is
*pass-by-reference*? - what is
*visibility*vs*scope*?

We started out in this course by writing functions with very simple control flow, as in these examples from labs 2 and 3:

These flowcharts show a very simple control flow: a *sequential* control flow
in which statements are executed, one after the other, until the function is
complete.
We then added to our function design toolkit by introducing
*branching* or *conditional* control flow.
This used `if`

statements to choose between two alternate possibilities,
allowing us to write more interesting functions like `onLine()`

from lab 4:

Then we started designing *loops*, which also employ conditions but use them to
perform actions zero or more times rather than zero times or once.
Loops allow us to tackle example problems in places like
Project Euler or, in fact, assignment 3!
Loops are also going to be a very important part of our remaining labs,
and were included in lab 4:

Now we will step back and think a bit more broadly about the functions we’ve
been writing.
In particular, we will think about how we use functions to
**build abstractions** that help us **solve problems**.

A graph (in this sense of the word) has nodes and edges.
We have already used flowcharts, in which the nodes are process boxes or
decision diamonds and the edges represent control flow.
Now, however, we can a new kind of graph to our repertoire: the *call graph*.
A call graph shows us how functions call other functions.
We can layer this kind of information on top of function flowcharts,
as shown here:

However, at a more abstract level (leaving out the details of what happens
*inside* each function), we can concentrate on the more **abstract**
call graph:

At each of these function calls, *arguments* from the function call are passed
into *parameters*.
So far in the course, we have seen these arguments be *passed by value*:
the values of the arguments are **copied into the parameters**
so that **parameters are independent of the values they were initialized by**:

Now, however, we will see a new way of passing arguments: *by reference*.

Sometimes we **don’t want** this independence of parameters from the values that
are used to initialize them.
Instead of passing arguments by value, in which copies get made of all the
values, we want to **share our variables with a function** and give
**permission for that function to use our variables directly**.
In C++, this is done using *pass-by-reference*.
In class, we discussed a `weather`

function that would retrieve the current
weather from a set of sensors.
That function will measure many things and need to “return” many values, but
so far we’ve only seen how to return a single value.
Using pass-by-reference, however, we can construct the following sort of call:

In this call, the `main`

function calls `weather`

and
**gives weather permission to modify some local variables of main**.
When the

`weather`

function takes its measurements, instead of returning them
to `main`

, it can `main`

variables that
it was passed references toThe syntax for C++ pass-by-references requires an additional ampersand (`&`

)
between a parameter’s type and name:

```
/**
* Report the current weather.
*
* @param[out] temperature the current temperature [degrees C]
* @param[out] humidity the current humidity [percent]
* @post humidity >= 0 and humidity <= 100
* @param[out] windSpeed the current wind speed [km/h]
*/
void weather(double& temperature, double& humidity, double& windSpeed);
/* ... */
void weather(double& temperature, double& humidity, double& windSpeed)
{
temperature = /* ... */;
humidity = /* ... */;
windSpeed = /* ... */;
}
```

Apart from this ampersand, the declaration and definition of the `weather`

function look just like something we could’ve written before.
What is different now is the meaning (semantics): instead of copying a value
into each parameter of `weather`

, we are giving `weather`

access to the local
variables of `main`

.
An important difference in the **call** to a pass-by-reference function is that
**we can only pass variables, not literal values**.
This is because we are no longer passing values, we’re passing references to
variables… so we need variables to have references to!

We can use pass-by-reference to implement lots of functions that would’ve been impossible with the tools we had before, e.g.:

```
void swap(int& x, int& y)
{
int temp = x;
x = y;
y = temp;
}
```

Now that we have some notion of how functions work, let’s talk about how to
use them in designed solutions to problems.
We have seen how functions can help up build up high-level abstractions from
lower-level ones, e.g., a function that makes a robot drive forwards will
*delegate* some of its work to lower-level functions that read sensors or
turn on the power on motor wheels.
This is a **bottom-up** approach to implementation.
Now, however, let’s look at how we can take a **top-down** approach to
problem solving by dividing it into smaller pieces (*divide and conquer*).
This is a common approach in many Engineering disciplines, and it is quite
effective in programming.

The top-down approach to procedural decomposition is:

- Divide the problem into independent sub-problems that are easier to solve.
- Start with a
*high-level*solution to the problem — many steps may be*abstract*(i.e., some of the implementation details remain unspecified). - Gradually refine solution into an concrete solution (i.e., algorithm) by adding detail.

**Problem:**
write a function to find the total mass of a batch of (identical) washers.

A washer is a doughnut-shaped disc of metal of uniform thickness whose mass is a product of its volume and its density. The mass of a batch would simply be the mass of an individual washer times the number of washers in the batch.

Find the mass of a batch of washers:

- Find the mass, $m$, of an individual washer
- Batch mass = $n \times w$

Now we *refine* the first step:

- Find the mass, $m$, of an individual washer
- Find the washer’s area, $A$
- Find the washer’s volume, $V = A \times d$ (depth)
- $m = V \times D$ (density)

- Batch mass = $n \times m$

We can also refine the first step of this refined step:

- Find the mass, $m$, of an individual washer
- Find the washer’s area, $A$
- Find the area of the outer circle, $A_0$
- Find the area of the inner circle, $A_1$
- $A = A_0 - A_1$

- Find the washer’s volume, $V = A \times d$ (depth)
- $m = V \times D$ (density)

- Find the washer’s area, $A$
- Batch mass = $n \times m$

Now, it seems like there’s still another refinement to be made:

To find the area of a circle: $A = \pi r^2$

Each of the **reusable** steps in our solution that involves
**creating an abstraction** (e.g., talking about total volume rather than the
lower-level details of inner/outer radii and depth) is a candidates
to be a **function**, even if a simple one.
Some examples of function declarations that we talked about in class include:

```
/**
* Calculates the volume of a washer-shaped object.
*
* @param r1 radius of the washer
* @param r2 radius of the washer's hole [same linear unit as r1]
*
* @pre r2 > 0, r2 < r1
*
* @returns total volume [same linear unit cubed]
*/
double washerVolume(double r1, double r2, double depth);
/**
* Calculates the area of a circle.
*
* @param radius radius of the circle @pre >= 0
*
* @returns the area of the circle [units of radius squared]
*/
double circleArea(double radius);
```

**Exercise:** write definitions for these and whatever other functions are
required to implement a complete solution to the above problem.

This is an exercise in *delegation*.
Each function delegates most of its work to an assistant function.
All the inputs (arguments) needed to carry out the whole problem are sent to the
topmost function.
It can simply passes four of its parameters over to a `washerMass`

function,
then multiplies the mass returned by that function by the count
in order to calculate the mass of the entire batch.
This is a very simple problem and the amount of delegation involved is fairly
extreme in that, once each function delegates, it has very little left to do.
Nevertheless, it illustrates the principle very well.

In practice, functions run from one line to hundreds of lines in length, with many functions being fewer than 20 lines. Once functions exceed 50–100 lines, it can be a sign that there are opportunities to break it into smaller, more reusable, pieces.

We have previously talked about variable scope, but what do we do when there are multiple variables in scope that have the same name? For example, in the following code:

```
int x;
void foo(int y)
{
if (y > 0)
{
int x = 17;
while (x > y)
{
int z = y / 2;
x -= z;
}
}
}
```

which `x`

variable is referenced by the statement `x -= z`

?
The answer is, when we have a choice of declarations that we might be referring
to, **we choose the most local one**.

- Write a function that will convert 2D
*cartesian*co-ordinates (i.e., $(x,y)$ co-ordinates) into*polar*co-ordinates (i.e., $(r,\theta)$). - Write a function that will compute the roots of a quadratic expression,
dealing with
**all special cases**(i.e., $a=0$ and $b^2 < 4ac$). - Using
`getNumberFromUser()`

from the examples page, write a function that will input an $(x,y,z)$ co-ordinate from a user and make it available to the function that called it.

(c) 2009â€“2016 Michael Bruce-Lockhart, Theo Norvell, Dennis Peters and Jonathan Anderson. Licensed under a Creative Commons Attributionâ€“Noncommercialâ€“Share-Alike 2.5 Canada License. Permissions beyond the scope of this license may be available at theteachingmachine.org.