Intermediate

Functions in MATLAB

Learn how to define and call functions in MATLAB — multiple return values, default arguments, recursion, anonymous functions, and higher-order functions with Docker-ready GNU Octave examples

Functions let you package logic into reusable, named units. In MATLAB they are central to writing anything beyond a short script: every toolbox you use is built from functions, and even the built-in disp and fprintf you met in Hello World are just functions.

MATLAB’s function model has a few characteristics that set it apart from many languages. Functions can return multiple values natively — no tuples, structs, or out-parameters required. Argument counts are flexible and inspected at runtime with nargin and nargout, which is how MATLAB handles “default” arguments. And because MATLAB is array-first, functions are typically written to operate on whole matrices at once rather than scalar-by-scalar.

This tutorial covers defining and calling functions, returning one or many values, default arguments, recursion, and anonymous functions (function handles) — MATLAB’s lightweight, first-class functions that enable higher-order programming with tools like arrayfun.

A note on file structure: In modern MATLAB (R2016b+) and in GNU Octave, a script file may contain local functions, but they must appear after all the script code. The examples below follow that order so they run unchanged in both environments.

Defining and Calling Functions

A function is introduced with the function keyword, names its outputs on the left of =, and is closed with end. The example below shows a single return value, MATLAB’s signature multiple return values, a default argument via nargin, and recursion.

Create a file named functions.m:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
% functions.m — defining, calling, and returning from functions

% Call a function that returns a single value
area = rectangle_area(4, 6);
fprintf('Area = %d\n', area);

% Capture multiple return values in one call
[s, p] = sum_and_product(4, 5);
fprintf('Sum = %d, Product = %d\n', s, p);

% Rely on a default argument (handled with nargin)
disp(power_of(3))       % exponent defaults to 2
disp(power_of(3, 3))    % exponent supplied explicitly

% Recursion: the classic factorial
fprintf('5! = %d\n', fact(5));

% --- Local function definitions (must follow the script code) ---

function a = rectangle_area(width, height)
    a = width * height;
end

function [s, p] = sum_and_product(a, b)
    s = a + b;        % first output
    p = a * b;        % second output
end

function result = power_of(base, exponent)
    if nargin < 2
        exponent = 2;     % default used when only one argument is passed
    end
    result = base ^ exponent;
end

function n = fact(k)
    if k <= 1
        n = 1;
    else
        n = k * fact(k - 1);   % function calls itself
    end
end

Key things to notice:

  • Outputs are named, not returned. You assign to the output variable(s); MATLAB returns whatever they hold when the function ends. There is no value-bearing return statement (a bare return just exits early).
  • Multiple outputs are listed in square brackets: [s, p] = sum_and_product(...). The caller decides how many to capture.
  • nargin (“number of arguments in”) reports how many arguments the caller actually passed, which is how you implement defaults.
  • Scope is local. Variables inside a function are private to it; they do not appear in the script’s workspace unless explicitly returned.

Anonymous Functions and Higher-Order Functions

MATLAB functions are first-class values through function handles. An anonymous function is created inline with the @(args) expression syntax and stored in a variable. Handles can capture surrounding variables and be passed to other functions — the foundation of higher-order programming in MATLAB.

Create a file named anonymous.m:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
% anonymous.m — anonymous functions and function handles

% An anonymous function stored in a handle
% Using .^ (element-wise power) so it works on scalars AND arrays
square = @(x) x.^2;
disp(square(5))

% Anonymous functions capture variables from the surrounding scope
factor = 10;
scale = @(x) x * factor;       % 'factor' is frozen into the handle
disp(scale(7))

% Pass a function handle into another function
disp(apply_twice(square, 3))

% Map a handle over an array with arrayfun, then print the result
values = [1 2 3 4];
squares = arrayfun(square, values);
fprintf('%d ', squares);
fprintf('\n');

% --- Local function definition ---

function y = apply_twice(f, x)
    y = f(f(x));      % f is itself a function handle
end

Key things to notice:

  • @(x) x.^2 defines an anonymous function of one argument. Using the element-wise operator .^ (rather than ^) means the same handle works on a scalar like 5 and on the vector values.
  • Closures: scale captures the value of factor at the moment the handle is created. Changing factor afterward would not affect scale.
  • Higher-order functions: apply_twice accepts another function as a parameter, and arrayfun applies a handle to every element of an array — array-friendly alternatives to writing explicit loops.

Running with Docker

MATLAB is commercial software, so we use GNU Octave, a free, largely MATLAB-compatible alternative. The same .m files run in both.

1
2
3
4
5
6
7
8
# Pull the GNU Octave image
docker pull gnuoctave/octave:9.4.0

# Run the functions example
docker run --rm -v $(pwd):/app -w /app gnuoctave/octave:9.4.0 octave --no-gui --no-window-system functions.m

# Run the anonymous functions example
docker run --rm -v $(pwd):/app -w /app gnuoctave/octave:9.4.0 octave --no-gui --no-window-system anonymous.m

Expected Output

Running functions.m:

Area = 24
Sum = 9, Product = 20
9
27
5! = 120

Running anonymous.m:

25
70
81
1 4 9 16 

Key Concepts

  • Functions name their outputs. Assign to the output variable(s) declared after function; there is no value-returning return statement.
  • Native multiple return values. List outputs in brackets — [s, p] = f(...) — and the caller chooses how many to capture, with nargout available inside the function to detect the count.
  • nargin/nargout drive flexible signatures. MATLAB has no built-in default-parameter syntax; you check the argument count and fill in defaults yourself.
  • Local functions live after the script code. A script file may define helper functions, but only below all the top-level statements (true in modern MATLAB and in Octave).
  • Anonymous functions are first-class. @(args) expr creates a function handle that can be stored, passed, and called like any value, capturing surrounding variables as a closure.
  • Prefer array operations over loops. With element-wise operators (.^, .*) and tools like arrayfun/cellfun, one function can process an entire matrix at once — the idiomatic MATLAB style.
  • Recursion works for naturally recursive problems like factorial, though MATLAB’s array operations are usually the faster, more idiomatic choice for bulk computation.

Running Today

All examples can be run using Docker:

docker pull gnuoctave/octave:9.4.0
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining