5. Functions#

Run this chapter online (or with solutions)

This chapter introduces the most important idea in computer programming: functions! To explain why functions are so important, I’ll start by explaining one of the problems they solve: name collisions.

Name Collisions#

All scripts run in the same workspace, so if one script changes the value of a variable, all other scripts see the change. With a small number of simple scripts, that’s not a problem, but eventually the interactions between scripts become unmanageable.

For example, the following script computes the sum of the first n terms in a geometric sequence, but it also has the side effect of assigning values to A1, total, i, and a.

A1 = 1;
total = 0;
for i=1:10
    a = A1 * 0.5^(i-1);
    total = total + a;
end
ans = total
ans = 1.9980

If you were using any of those variable names before calling this script, you might be surprised to find, after running the script, that their values had changed. If you have two scripts that use the same variable names, you might find that they work separately and then break when you try to combine them. This kind of interaction is called a name collision.

As the number of scripts you write increases, and they get longer and more complex, name collisions become more of a problem. Avoiding this problem is one of several motivations for functions.

Defining Functions#

A function is like a script, except that each function has its own workspace, so any variables defined inside a function only exist while the function is running and don’t interfere with variables in other workspaces, even if they have the same name. Function inputs and outputs are defined carefully to avoid unexpected interactions.

To define a new function, you create an M-file with the name you want and put a function definition in it. For example, to create a function named myfunc, create an M-file named myfunc.m and put the following definition into it (Listing 5.1):

Listing 5.1: A function definition

function res = myfunc(x)
    s = sin(x)
    c = cos(x)
    res = abs(s) + abs(c)
end

The first non-comment word of the file has to be function, because that’s how MATLAB tells the difference between a script and a function file.

A function definition is a compound statement. The first line is called the signature of the function; it defines the inputs and outputs of the function. In Listing 5.1 the input variable is named x. When this function is called, the argument provided by the user will be assigned to x.

The output variable is named res, which is short for result. You can call the output variable whatever you want, but as a convention, I like to call it res. Usually the last thing a function does is assign a value to the output variable.

Once you’ve defined a new function, you call it the same way you call built-in MATLAB functions. If you call the function as a statement, MATLAB puts the result into ans:

myfunc(1)
s = 0.8415
c = 0.5403
res = 1.3818
ans = 1.3818

But it’s more common (and better style) to assign the result to a variable:

y = myfunc(1)
s = 0.8415
c = 0.5403
res = 1.3818
y = 1.3818

While you’re debugging a new function, you might want to display intermediate results like this, but once it’s working, you’ll want to add semicolons to make it a silent function. A silent function computes a result but doesn’t display anything (except sometimes warning messages). Most built-in functions are silent.

Each function has its own workspace, which is created when the function starts and destroyed when the function ends. If you try to access (read or write) the variables defined inside a function, you will find that they don’t exist.

clear
y = myfunc(1);
who
s

In MATLAB, the output is:

Your variables are: y

Undefined function or variable 's'.

In Octave, the error message is:

error: 's' undefined

The only value from the function that you can access is the result, which in this case is assigned to y.

If you have variables named s or c in your workspace before you call myfunc, they will still be there when the function completes.

s = 1;
c = 1;
y = myfunc(1);
s, c
s = 0.8415
c = 0.5403
res = 1.3818
s = 1
c = 1

So inside a function you can use whatever variable names you want without worrying about collisions.

Function Documentation#

At the beginning of every function file, you should include a comment that explains what the function does:

% res = myfunc(x)
% Compute the Manhattan distance from the origin to the
% point on the unit circle with angle (x) in radians.

function res = myfunc(x)
% this is not part of documentation given by help function

    s = sin(x);
    c = cos(x);
    res = abs(s) + abs(c);
end

When you ask for help, MATLAB prints the comment you provide.

help myfunc
'myfunc' is a command-line function

 this is not part of documentation given by help function


Additional help for built-in functions and operators is
available in the online version of the manual.  Use the command
'doc <topic>' to search the manual index.

Help and information about Octave is also available on the WWW
at https://www.octave.org and https://octave.discourse.group/c/help/

There are lots of conventions about what should be included in these comments. Among other things, it’s a good idea to include the following:

  • Signature: The signature of the function, which includes the name of the function, the input variable(s), and the output variable(s).

  • Description: A clear, concise, abstract description of what the function does. An abstract description is one that leaves out the details of how the function works and includes only information that someone using the function needs to know. You can put additional comments inside the function that explain the details.

  • Variables: An explanation of what the input variables mean; for example, in this case it is important to note that x is considered to be an angle in radians.

  • Conditions: Any preconditions and postconditions.

Naming Functions#

There are a few “gotchas” that come up when you start defining functions. The first is that the “real” name of your function is determined by the file name, not by the name you put in the function signature. As a matter of style, you should make sure that they are always the same, but if you make a mistake, or if you change the name of a function, it’s easy to get confused.

In the spirit of making errors on purpose, edit myfunc.m and change the name of the function from myfunc to something_else, like this:

function res = something_else (x)
    s = sin(x);
    c = cos(x);
    res = abs(s) + abs(c);
end

In a notebook, functions are defined by running cells, not by files, so this cell is shown as text; running it would define a function named something_else.

Now call the function from the Command Window, like this:

y = myfunc(1)
y = 1.3818

The function is still called myfunc, because that’s the name of the file. If you try to call it like this:

y = something_else(1)

In MATLAB, the error message is:

Undefined function or variable 'something_else'.

In Octave, it is:

error: 'something_else' undefined

It doesn’t work. The name of the file is what matters; the name of the function is ignored.

The second “gotcha” is that the name of the file can’t have spaces. For example, if you rename the file to my func.m and try to run it, you get:

y = my func(1)

In MATLAB, the error message is:

 y = my func(1)
        |
Error: Unexpected MATLAB expression.

In Octave, it is:

parse error:

  syntax error

This fails because MATLAB thinks my and func are two different variable names.

The third “gotcha” is that your function names can collide with built-in MATLAB functions. For example, if you create an M-file named sum.m and then call sum, MATLAB might call your new function, not the built-in version! Which one actually gets called depends on the order of the directories in the search path and (in some cases) on the arguments. As an example, put the following code in a file named sum.m:

function res = sum(x)
   res = 7;
end

And then try this:

>> sum(1:3)

ans = 6

>> sum

ans = 7

These two cells are shown as text: in a notebook, defining a function named sum would replace the built-in sum for the rest of the notebook.

In the first case MATLAB used the built-in function; in the second case it ran your function! This kind of interaction can be very confusing. Before you create a new function, check to see if there is already a MATLAB function with the same name. If there is, choose another name!

Multiple Input Variables#

Functions can take more than one input variable. For example, the following function in Listing 5.2 takes two input variables, a and b:

Listing 5.2: A function that computes the sum of squares of two numbers

function res = sum_squares(a, b)
    res = a^2 + b^2;
end

This function computes the sum of squares of two numbers, a and b.

If we call it from the Command Window with arguments 3 and 4, we can confirm that the sum of their squares is 25.

ss = sum_squares(3, 4)
ss = 25

The arguments you provide are assigned to the input variables in order, so in this case 3 is assigned to a and 4 is assigned to b. MATLAB checks that you provide the right number of arguments; if you provide too few, you get

ss = sum_squares(3)

In MATLAB, the error message is:

Not enough input arguments.

Error in sum_squares (line 4)
    res = a^2 + b^2;

In Octave, it is:

error: 'b' undefined

This error message might be confusing, because it suggests that the problem is in sum_squares rather than in the function call. Keep that in mind when you’re debugging.

If you provide too many arguments, you get

>> ss = sum_squares(3, 4, 5)
Error using sum_squares
Too many input arguments.

In Octave, it is:

error: sum_squares: function called with too many inputs

That’s a better error message, because it’s clear that the problem isn’t in the function, it’s in the way we’re using the function.

Chapter Review#

Now that we know about functions, and all the ways they can go wrong, let’s put them to good use. In the next chapter we’ll develop a program that uses several functions to search for Pythagorean triples (and I’ll explain what those are).

Here are a few terms in this chapter you might want to remember.

A function is a named sequence of statements stored in an M-file. A function can have one or more input variables, which get their values when the function is called, and output variables, which return a value from the function to the caller.

The first line of a function definition is its signature, which specifies the name of the function, the input variables, and the output variables.

A silent function doesn’t display anything, generate a figure, or have any other effect other than returning output values.

Exercise#

Before you go on, you might want to work on the following exercise.

Exercise 5.1. Write a function called hypotenuse that takes two parameters, a and b, that represent the lengths of two sides of a right triangle. It should assign to res the length of the third side of the triangle, given by the formula

\[c = \sqrt{a^2 + b^2}\]

Hide solution

% Solution

% Compute the hypotenuse of a right triangle.

function res = hypotenuse(a, b)
    res = sqrt(a^2 + b^2);
end

Hide solution

% Solution

hypotenuse(3, 4)
ans = 5