This note aims at explaining the concepts of functions as program units.

What is a Function?

Functions in programming languages are self-contained modules of code that accomplish a specific task. They usually (but not always) take some data as input, process the input data, and return a result. Therefore, the definition of function in programming goes far beyond the mathematical definition of a function. For example, programming functions can have no input or output.

The main reason for writing functions is to reduce coding redundancy and increase code reuse. Once a function is written, it can be used over and over and over again. Whenever a function is needed, it can be called from the inside of the main program or from inside of other functions.

In MATLAB, like most other programming languages, function is a collection of programming statements that can be executed whenever and wherever requested. Both MATLAB scripts and functions allow you to reuse sequences of commands by storing them in program files. Scripts are the simplest type of program since they store commands exactly as you would type them at the command line. Functions provide more flexibility, primarily because you can pass input values and return output values. The general syntax for a MATLAB function is the following,

function [y1,...,yN] = myfunc(x1,...,xM)
    % here is the body of the function

The above declares a function named myfunc that accepts inputs x1,...,xM and returns outputs y1,...,yN. This declaration statement must be the first executable line of the function. Just like MATLAB variables, valid function names begin with an alphabetic character and can contain letters, numbers, or underscores.

You can save your function in,

  • a function file which contains only function definitions. The name of the file should match the name of the first function in the file.
  • a script file which contains commands and function definitions. Functions must be at the end of the file. This may seem a bit odd to you, if you already know other programming languages, for example, Python. Script files cannot have the same name as a function in the file. Functions in scripts are supported only in MATLAB R2016b or later.

Files can include multiple local functions or nested functions. For readability, use the optional end keyword to indicate the end of each function in a file. The end keyword is required when,

  • Any function in the file contains a nested function.
  • The function is a local function within a function file, and any local function in the file uses the end keyword.
  • The function is a local function within a script file.

In general, it is always good to add the end keyword to all functions, for better readability.

Example

Let’s write a MATLAB function that takes in a temperature value in Centigrade and converts it to Fahrenheit.

function [F] = c2f(C)
    F = (9.0/5)*C + 32;
end

Answer

c_temp = 70.7; % The hottest place on Earth, Lut Desert in Iran 
f_temp = c2f(c_temp);
disp(['Temperature in Fahrenheit: ',num2str(f_temp)])
disp( ['The hottest place on Earth as of 2005 is in the Lut Desert in Iran at ' ...
      , num2str(70.7) ...
      , ' degrees Celsius.',char(10) ...
      , 'This corresponds to a temperature of ', num2str(159.26), ' degrees Fahrenheits!' ...
      ] );
The temperature in Fahrenheit: 159.26
The hottest place on Earth as of 2005 is in the Lut Desert in Iran at 70.7 degrees Celsius.
This corresponds to a temperature of 159.26 degrees Fahrenheit!

Functions with no input arguments

We can define functions that take no input argument, yet do something predefined for us. Consider the following function which outputs information about the field of Data Science when called.

function info = get_info()
    info = 'Data science is a multi-disciplinary field that uses scientific methods, processes, algorithms, and systems to extract knowledge and insights from structured and unstructured data.';
end
>> out = get_info()
Data science is a multi-disciplinary field that uses scientific methods, processes, algorithms, and systems to extract knowledge and insights from structured and unstructured data.

Functions with no output (return value)

We can also modify the above function such that it does not return anything specifically.

function get_info()
    disp('Data science is a multi-disciplinary field that uses scientific methods, processes, algorithms and systems to extract knowledge and insights from structured and unstructured data.');
end
>> get_info()
Data science is a multi-disciplinary field that uses scientific methods, processes, algorithms and systems to extract knowledge and insights from structured and unstructured data.

This is almost equivalent to the word void in languages like Java, C, and C++. If you set a variable equal to this function, you will get an error message, because the function does not return anything as output.

>> out = get_info()
Error using get_info
Too many output arguments.

Functions with multiple input arguments

Functions can take almost as many input arguments as we wish. Consider the following that takes two arguments,

function result = mypower(base,exponent)
    result = base^exponent;
    return
end
>> mypower(10,2)
ans =
   100

Variable number of input arguments

The functions that we have written thus far have contained a fixed number of input arguments and a fixed number of output arguments. But you can also define a MATLAB function that accepts a variable number of inputs. In this case, you use MATLAB’s builtin input argument cell varargin in place of the arbitrary number of input arguments. The function nargin returns the number of input arguments that were passed to the function. For example, consider the following function that displays the values of each input to the function,

function varlist(year,varargin)
   fprintf('Number of arguments: %d\n',nargin)
   celldisp(varargin)
   fprintf('The year is %d\n',year)
   fprintf('type of varargin is %s\n',class(varargin))
end
>> varlist(2017,'what','a ','nice', 'weather')
Number of arguments: 5
varargin{1} =
what 
varargin{2} =
a 
varargin{3} =
nice 
varargin{4} =
weather 
The year is 2017
type of varargin is cell

You can find more information about input/ouput function arguments here.

Optional arguments using inputParser

Unlike other languages such as Python, Fortran, and C++, there is no simple direct way of having optional arguments in MATLAB functions, other than the one described above, using varargin. However, MATLAB has a powerful set of built-in capabilities known as inputParser for parsing the input arguments of a given function. The usage and details of this method go beyond the scope of this class. However, you can learn more about it here.

Functions with multiple output (return values)

MATLAB functions can also return more than one output value. The output could be of any type: vector, matrix, cell, structure, etc. For example, consider a function that takes an input vector of double and calculates its mean and standard deviation.

function [m,s] = stat(x)  % a function that returns the result as vector of length two
    n = length(x);
    m = sum(x)/n;
    s = sqrt(sum((x-m).^2/n));
end
>> values = [12.7, 45.4, 98.9, 26.6, 53.1];
>> stat(values)
ans =
   47.3400

Notice that if you don’t provide two output arguments, then basically only one is reported.

>> valuesMean = stat(values)
valuesMean =
   47.3400
>> [valuesMean, valuesStd] = stat(values)
valuesMean =
   47.3400
valuesStd =
   29.4124
>> [valuesMean, valuesStd, dummy] = stat(values)   % too many output arguments is meaningless
Error using stat
Too many output arguments. 
function [x,result] = stat(x) % the same function as above, but now returning the result as a structure, together with input x
    result = struct();
    result.n = length(x);
    result.mean = sum(x) / result.n;
    result.std = sqrt( sum( (x-result.mean).^2 / result.n ) );
end
>> values = [12.7, 45.4, 98.9, 26.6, 53.1];
>> stat(values)
ans =
   12.7000   45.4000   98.9000   26.6000   53.1000
>> [input,ouput] = stat(values)
input =
   12.7000   45.4000   98.9000   26.6000   53.1000
ouput = 
       n: 5
    mean: 47.3400
     std: 29.4124

Exercise

Write a function that takes in three coefficients $(a,b,c)$ of a quadratic equation $ax^2+bx+c$ and finds the roots of this equation.

Answer

function [x1,x2] = quadform(a,b,c)
    d = sqrt(b^2 - 4*a*c);
    x1 = (-b + d) / (2*a);
    x2 = (-b - d) / (2*a);
end
>> [r1,r2] = quadform(1,1,1)
r1 =
  -0.5000 + 0.8660i
r2 =
  -0.5000 - 0.8660i

Variable number of output arguments

A variable number of output arguments can also be specified. For example, consider the following function typesize() which takes one input argument inputval. The function will always return a character specifying whether the input argument was a scalar (‘s’), vector (‘v’), or matrix (‘m’). This character is returned through the output argument arrtype. Additionally, if the input argument was a vector, the function also returns the length of the vector, and if the input argument was a matrix, the function returns the number of rows and the number of columns of the matrix. The MATLAB’s builtin output argument varargout is used, which is a cell array. So, for a vector, the length is returned through varargout and for a matrix, both the number of rows and columns are returned through varargout,

function [arrtype, varargout] = typesize(inputval)
    % typesize returns a character 'scalar' for scalar, 'vector'
    % for vector, or 'matrix' for matrix input argument
    % also returns length of a vector or dimensions of matrix
    % Format: typesize(inputArgument)
    [nrow, ncol ] = size(inputval);
    if nrow==1 && ncol==1
    arrtype = 'scalar';
    elseif nrow==1 || ncol==1
    arrtype = 'vector';
    varargout{1} = length(inputval);
    else
    arrtype = 'matrix';
    varargout{1} = nrow;
    varargout{2} = ncol;
    end
end
>> typesize(10)
ans =
scalar
>> typesize(10:12)
ans =
vector
>> [inputType,inputLength] = typesize(10:12)
inputType =
vector
inputLength =
     3
>> [inputType,nrow,ncol] = typesize([10:12;13:15])
inputType =
matrix
nrow =
     2
ncol =
     3

Function handles in MATLAB

Function Handles are variables that allow you to invoke a function indirectly. A function handle is a data type that stores an association to a function. For example, you can use a function handle to construct anonymous functions or specify call-back functions. Also, you can use a function handle to pass a function to another function, or call local functions from outside the main function (see below).

Indirectly calling a function enables you to invoke the function regardless of where you call it from. Typical uses of function handles include:

  • Pass a function to another function (often called function functions). For example, passing a function to integration or optimization functions as we will see later in this course, such as integral and fzero.
  • Construct handles to functions defined inline instead of stored in a program file (anonymous functions).
  • Call local functions from outside the main function.

You can see if a variable, say h, is a function handle using isa(h,'function_handle').

Creating function handle

The general method for creating a function handle is to precede the function name with an @ sign. For example, if you have a function called myfunc, you can create a handle named f for it as follows,

f = @myfunc;

For example,

function out = getSq(x)
    out = x.^2;
end

Then you can create a function handle on MATLAB command line like the following,

>> f = @getSq;
>> a = 4;
>> b = f(a)
b =
    16

If the function does not require any inputs, then you can call the function with empty parentheses. For example,

>> h = @ones;
>> a = h()
a =
     1

If you don’t add () at the time of call, then simply another function handle will be created, now assigned to a,

>> h = @ones;
>> a = h
a = 
    @ones
>> class(a)
ans =
function_handle

Function handles can be passed as variables to other functions. For example, to calculate the integral of $f(x)=x^2$, as implemented in getSq() above, on the range $[0,1]$ define,

>> f = @getSq; 
>> q = integral(f,0,1)
q =
    0.3333

Arrays of function handles

You can also create an array of function handles by collecting them into a cell or structure array. For example,

>> fset = {@sin, @cos, @tan, @cot};
>> fset{1}(pi)
ans =
   1.2246e-16
>> fset{2}(pi)
ans =
    -1
>> fset{3}(pi)
ans =
  -1.2246e-16
>> fset{4}(pi)
ans =
  -8.1656e+15

To get general information about a function handle on MATLAB command line, use,

>> functions(fset{4})
ans = 
    function: 'cot'
        type: 'simple'
        file: ''

Function types in MATLAB

There are several types of functions in MATLAB. These include,

  • local functions,
  • nested functions,
  • private functions,
  • function functions,
  • anonymous functions

Anonymous functions

Anonymous functions allow you to create a MATLAB file without the need to put the function in a separate .m file dedicated to the function. This function is associated with a variable whose data type is function_handle. Anonymous functions can accept inputs and return outputs, just as standard functions do. However, they can contain only a single executable statement. The concept of the anonymous function is similar to lambda functions in Python, if you are already familiar with this language. For example, consider the following handle to an anonymous function that finds the square of a number,

>> sq = @(x) x.^2;
>> sq(2)
ans =
     4
>> sq([2,3,4])
ans =
     4     9    16

Variables in anonymous function expressions

Function handles can store not only an expression but also variables that the expression requires for evaluation. For example, you can create a function handle to an anonymous function that requires coefficients a, b, and c.

>> a = 1.3;
>> b = .2;
>> c = 30;
>> parabola = @(x) a*x.^2 + b*x + c;

Since a, b, and c are available at the time you create parabola, the function handle includes those values. The values persist within the function handle even if you clear the variables,

>> clear a b c
>> x = 1;
>> y = parabola(x)
y =
   31.5000

But note that in order to supply different values for the coefficients, you must create a new (e.g., redefine the) function handle,

>> a = -3.9;
>> b = 52;
>> c = 0;
>> parabola = @(x) a*x.^2 + b*x + c;
>> x = 1;
>> y = parabola(x)
y =
   48.1000

Multiple (nested) anonymous functions

The expression in an anonymous function can include another anonymous function. This is useful for passing different parameters to a function that you are evaluating over a range of values. For example, suppose you want to solve the following equation for varying values of the variable c,

You can do so by combining two anonymous functions,

g = @(c) (integral(@(x) (x.^2 + c*x + 1),0,1));

Here are the steps to derive the above nested anonymous functions,

  • Write the integrand as an anonymous function,
    @(x) (x.^2 + c*x + 1)
    
  • Evaluate the function from zero to one by passing the function handle to integral,
    integral(@(x) (x.^2 + c*x + 1),0,1)
    
  • Supply the value for c by constructing an anonymous function for the entire equation,
    g = @(c) (integral(@(x) (x.^2 + c*x + 1),0,1));
    

The final function allows you to solve the equation for any value of c. For example,

>> g(10)
ans =
    6.3333

Anonymous functions with no input

If your function does not require any inputs, use empty parentheses when you define and call the anonymous function. Otherwise, as stated above in function handles, you will simply create a new function handle. For example,

>> t = @() datestr(now);
>> d = t()
d =
23-May-2017 19:54:07

and omitting the parentheses in the assignment statement creates another function handle, and does not execute the function,

>> d = t
d = 
    @()datestr(now)

Anonymous functions with multiple inputs or outputs

Anonymous functions require that you explicitly specify the input arguments, as many as it may be, just the way you would for a standard function, separating multiple inputs with commas. For example, the following function accepts two inputs, x and y,

>> myfunc = @(x,y) (x^2 + y^2 + x*y);
>> x = 1;
>> y = 10;
>> z = myfunc(x,y)
z =
   111

However, you do not explicitly define output arguments when you create an anonymous function. If the expression in the function returns multiple outputs, then you can request them when you call the function. In that case, you should enclose multiple output variables in square brackets []. For example, MATLAB’s ndgrid function can return as many outputs as the number of input vectors. This anonymous function that calls ndgrid can also return multiple outputs,

mygrid = @(x,y,c) ndgrid((-x:x/c:x),(-y:y/c:y));
[X,Y] = mygrid(pi,2*pi,10);

You can use the output from mygrid to create a mesh or surface plot, like the following, as we will further discuss in the future notes on plotting in MATLAB,

Z = sin(X) + cos(Y);
mesh(X,Y,Z)

Arrays of anonymous functions

As we did above for MATLAB function handles, you can also store multiple anonymous functions in a cell array or structure array. The most common approach is to use a cell array, like the following,

f = {@(x)x.^2;
     @(y)y+10;
     @(x,y)x.^2+y+10
     };

When you create the cell array, keep in mind that MATLAB interprets spaces as column separators for the cell array. Either omit spaces from expressions, as shown in the previous code or enclose expressions in parentheses such as,

f = {@(x) (x.^2);
     @(y) (y + 10);
     @(x,y) (x.^2 + y + 10)
     };

Access the contents of a cell using curly braces. For example, f{1} returns the first function handle. To execute the function, pass input values in parentheses after the curly braces,

>> x = 1;
>> y = 10;
>> f{1}(x)
ans =
     1
>> f{2}(y)
ans =
    20
>> f{3}(x,y)
ans =
    21

Local functions

MATLAB program files can contain code for more than one function. In a function file, the first function in the file is called the main function. This function is visible to functions in other files, or you can call it from the command line. Additional functions within the file are called local functions, and they can occur in any order after the main function. Local functions are only visible to other functions in the same file. They are equivalent to subroutines in other programming languages and are sometimes called subfunctions.

As of R2016b, you can also create local functions in a script file, as long as they all appear after the last line of script code. For more information, see here.

Exercise

Create a function file named mystats.m that takes as input a given vector of real numbers and outputs the mean and median of the vector. The .m file for this function should contain contains a main function mystats(), and two local functions, mymean and mymedian. Test your main function using an input vector-like,

>> myvec = [10:3:100];
>> mystats(myvec)
ans =
    55

Answer

function [avg, med] = mystats(x)
    n = length(x);
    avg = mymean(x,n);
    med = mymedian(x,n);
end

function a = mymean(v,n)
    % MYMEAN Example of a local function.
    a = sum(v)/n;
end

function m = mymedian(v,n)
    % MYMEDIAN Another example of a local function.
    
    w = sort(v);
    if rem(n,2) == 1
        m = w((n + 1)/2);
    else
        m = (w(n/2) + w(n/2 + 1))/2;
    end
end

Note that you cannot call the local functions, because local functions are not visible to any other place or function in MATLAB other than mystats().

>> mymean(myvec,length(myvec))
Undefined function or variable 'mymean'. 
Did you mean:
>> mean(myvec,length(myvec))

Collective function handle for all local functions

MATLAB has a built-in function localfunctions that returns a cell array of all local functions in the scope of the current function or script (i.e., in the current MATLAB file). This is very useful when you want to write a function that returns to the main program, a list of functions local to this function. For example,

function fh = computeEllipseVals
    fh = localfunctions;
end

function f = computeFocus(a,b)
    f = sqrt(a^2-b^2);
end

function e = computeEccentricity(a,b)
    f = computeFocus(a,b);
    e = f/a;
end

function ae = computeArea(a,b)
    ae = pi*a*b;
end

Now, if you call computeEllipseVals on the command prompt, you will get a cell array to all functions local to computeEllipseVals,

>> fhcell = computeEllipseVals
ans = 
    @computeFocus       
    @computeEccentricity
    @computeArea
>> fhcell{3}(1,1) % get the area of an ellipse with semi-axes (1,1).
ans =
    3.1416

Function functions

Function-functions are functions that operate on other functions that are passed to it as input arguments. The function that is passed to the function-function is usually referred to as passed function. A simple example is MATLAB’s built-in function fplot(func,lim), which plots the given input function func to it within the limit lim,

fplot(@sin,[-2*pi 2*pi])

Nested functions

Nested functions, as implicitly described by their names, are completely contained within a parent function. Any function in a program file can include a nested function. For example, consider the following simple function nestedfunc() inside of its parent function parent(),

function parent
    disp('This is the parent function')
    nestedfunc
    function nestedfunc
       disp('This is the nested function')
    end
end
>> parent
This is the parent function
This is the nested function

The primary difference between nested functions and other types of functions is that they can access and modify variables that are defined in their parent functions. Therefore, nested functions can use variables that are not explicitly passed as input arguments. In a parent function, you can create a handle to a nested function that contains the data necessary to run the nested function.

Requirements for Nested Functions

  • Although MATLAB functions do not typically require an end statement, to nest any function in a program file, all functions in that file must use an end statement.

  • You cannot define a nested function inside any of the MATLAB program control statements, such as if/elseif/else, switch/case, for, while, or try/catch.

  • You must call a nested function either directly by name (without using feval), or using a function handle that you created using the @ operator (and not str2func).

  • All of the variables in nested functions or the functions that contain them must be explicitly defined. That is, you cannot call a function or script that assigns values to variables unless those variables already exist in the function workspace.

  • In general, variables in one function workspace are not available to other functions. However, nested functions can access and modify variables in the workspaces of the functions that contain them. This means that both a nested function and the parent function that contains it can modify the same variable without passing that variable as an argument. For example, in each of these functions, main1() and main2, both parent functions and the nested functions can access variable x,

    function main1
      x = 5;
      nestfun1
      function nestfun1 
          x = x + 1;
      end
      disp(['x = ',num2str(x)])
    end
    
    function main2
      nestfun2
      function nestfun2
          x = 5;
      end 
      x = x + 1;
      disp(['x = ',num2str(x)])
    end
    
    >> main1
    
    x = 5
    
    >> main1()
    
    x = 6
    
    >> main2()
    
    x = 6
    

When the parent function does not use a given variable, the variable remains local to the nested function. This is rather subtle and complicated. So pay attention. For example, in this function named main, the two nested functions have their own versions of externFunc that cannot interact with each other and, calling main gives a syntax error in nestedfun2, since myvar is undefined,

function main
    nestedfun1
    nestedfun2
    function nestedfun1
        myvar = 10;
        xyz = 5;
    end
    function nestedfun2
        myvar = myvar + 2;
    end
end
>> main
Undefined function or variable 'myvar'.
Error in main/nestedfun2 (line 10)
        myvar = myvar + 2;
Error in main (line 3)
    nestedfun2

However, even the slightest mention of the variable myvar, like the following, makes it accessible in the scope of both main and nested functions.

function main
    nestedfun1
    nestedfun2
    
    function nestedfun1
        myvar = 10;
    end

    function nestedfun2
        myvar = myvar + 2;
    end
    disp(['myvar = ',num2str(myvar)]);
    disp(['class(myvar) = ',class(myvar)]);
end
>> main
myvar = 12
class(myvar) = double

However, if there is any other function in MATLAB path that has the same name as this variable myvar, then MATLAB by default will call the function, instead of invoking the value for this variable given by the nested functions. For example, if the following function is in the MATLAB path,

function result = myvar
    result = -13;
end

then calling the same function main as above would give,

>> main
myvar = -13
class(myvar) = double

The scope of variables in MATLAB functions, especially nested functions, can become a significant source of error and confusion in your MATLAB code if you are not careful. As a result, MATLAB’s code editor has special syntax-highlighting features for variables that are shared between nested functions and is very smart in automatically detecting syntax or semantic errors in your codes. So, I always recommend you to use MATLAB’s own editor and debugger. You can find more information about this issue here.

Private Functions

A typical modern MATLAB contains thousands of M-files on the user’s path, all accessible just by typing the name of the M-file. While this ease of accessing M-files is an advantage, it can lead to clutter and clashes of names, not least due to the presence of helper functions that are used by other functions but not intended to be called directly by the user. Private functions provide an elegant way to avoid these problems. Any functions residing in a directory called private are visible only to functions in the parent directory. They can, therefore, have the same names as functions in other directories. When MATLAB looks for a function it searches subfunctions, then private functions (relative to the directory in which the function making the call is located), then the current directory and the path. Hence if a private function has the same name as a nonprivate function (even a built-in function), the private function will be found first.

Recursive functions

In programming, a recursive function is a function that calls itself. Recursion is needed frequently in programming, although there might be better, more efficient ways of implementing many of the simple explanatory recursion examples that you find in programming books. A prominent and sometimes more efficient alternative to recursive programming is iterative methods. Nontrivial examples that require recursive programming are abundant but go beyond the scope of this course.

To begin, let’s write a simple function that takes in one positive integer $n$, and calculates its factorial,

function result=getFactorial(x)
    if (x<=0)
        result=1;
    else
        result=x*getFactorial(x-1);
    end
end
>> getFactorial(3)
ans =
     6

Exercise

Consider the MATLAB intrinsic function strtok, which returns the first token (word) in a given string (sentence). Now, write a recursive MATLAB function that reverses the input sentence given by the user like the following,

>> reverseSentence('MATLAB is a rather strange but very powerful programming language')
language programming powerful very but strange rather a is MATLAB 

Answer

function reverseSentence(string)
    % reverseSentence recursively prints the words in a string in reverse order    
    getToken(string)
    function getToken(string)
        [word, rest] = strtok(string);
        if ~isempty(rest)
            getToken(rest);
        end
        fprintf([word,' '])
    end
    fprintf('\n')
end

MATLAB’s intrinsic functions

You may have already noticed that functions are among the most useful concepts in programming. MATLAB owes its popularity to more 10000 built-in functions that it contains, and the number is growing every year. That means we don’t need to write programs for more than 10000 important general tasks that we may need to do every day, for example, integration, differentiation, various types of plotting, root finding and many more.

A comprehensive list of MATLAB’s built-in functions is available in MATLAB manual. I recommend you to bookmark this link on your personal computer, to get help from it whenever you need. As a reminder, the following list contains some useful MATLAB functions, some of which we also discussed in the previous sections. Search for their cool functionalities in MATLAB manual!

  • doc
  • func2str
  • str2func
  • fplot
  • feval
  • fzero
  • which
  • edit
  • type

Note that you can use the first one (doc) to view the information all the rest, even itself!