Anonymous Functions and Function Handles

A function handle (@name) is a value that refers to a function: store it in a variable, pass it to another function, call it later.

Concept

A function handle (@name) is a value that refers to a function: store it in a variable, pass it to another function, call it later.

An anonymous function defines a one-expression function inline: sq = @(x) x.^2. It captures the values of any other variables at the moment it is created (later changes to those variables don't affect it).

Handles are everywhere in MATLAB's numerical library: fzero(@f, x0), integral(@f, a, b), ode45(@rhs, tspan, y0), fminsearch, arrayfun, cellfun, callbacks in GUIs.

arrayfun(@f, A) Apply f to each element of an array cellfun(@f, C) Apply f to each cell of a cell array 'UniformOutput', false

Collect results in a cell array when they aren't scalars func2str, str2func Convert between handles and text

Why It Matters

Handles let you write general tools (a solver, an optimizer, a test runner) that work with any model function — the core of numerical engineering code.

Syntax

f = @(t, y) -2 * y;                 % anonymous
h = @sin;                           % handle to a named function
integral(f_of_x, 0, 1);            % pass as an argument
C = cellfun(@upper, names, 'UniformOutput', false);

Example

12.1 Anonymous functions, captured variables, handles as arguments

sq = @(x) x .^ 2;                                 % anonymous function
fprintf('sq(4) = %g, sq([1 2 3]) = %s\n', sq(4), mat2str(sq([1 2 3])))

g = 9.81;
fall = @(t) 0.5 * g * t .^ 2;                      % captures g's value at creation
g = 1.62;
fprintf('fall(2) = %.2f m (still uses g = 9.81)\n', fall(2))

h = @celsius_to_fahrenheit;                        % handle to a named function
fprintf('h(37) = %.1f, func2str(sq) = %s\n', h(37), func2str(sq))

apply = @(f, v) f(v);                              % functions as arguments
fprintf('apply(@sqrt, 81) = %g\n', apply(@sqrt, 81))

fprintf('arrayfun: %s\n', mat2str(arrayfun(@(k) k * 10, 1:4)))
lens = cellfun(@length, {'VCU', 'BMS', 'Gateway'});
fprintf('cellfun lengths: %s\n', mat2str(lens))
up = cellfun(@upper, {'vcu', 'bms'}, 'UniformOutput', false);
fprintf('cellfun with UniformOutput false: %s\n', strjoin(up, ', '))

fprintf('fzero(@(x) x^2 - 2, 1) = %.6f\n', fzero(@(x) x^2 - 2, 1))
fprintf('integral of sin from 0 to pi = %.6f\n', integral(@sin, 0, pi))

compose = @(f, g2) @(x) f(g2(x));
kmh_rounded = compose(@round, @(mps) mps * 3.6);
fprintf('compose: 27.78 m/s -> %d km/h\n', kmh_rounded(27.78))

Expected Result

fall kept using g = 9.81 even after g was changed to 1.62: anonymous functions capture values when created. fzero and integral both took a handle as their first argument.

sq(4) = 16, sq([1 2 3]) = [1 4 9]
fall(2) = 19.62 m (still uses g = 9.81)
h(37) = 98.6, func2str(sq) = @(x) x .^ 2
apply(@sqrt, 81) = 9
arrayfun: [10 20 30 40]
cellfun lengths: [3 3 7]
cellfun with UniformOutput false: VCU, BMS
fzero(@(x) x^2 - 2, 1) = 1.414214
integral of sin from 0 to pi = 2.000000
compose: 27.78 m/s -> 100 km/h

Common Mistakes

Using * instead of .* inside an anonymous function that must work on vectors.

Expecting an anonymous function to see later changes of captured variables.

cellfun failing with "non-uniform output" — add 'UniformOutput', false.

Multi-statement logic in an anonymous function (not allowed; write a normal function).

Best Practices

Keep anonymous functions short; name complex ones as proper functions.

Parameterize models by capturing parameters: rhs = @(t, y) model(t, y, p).

Prefer vectorized code over arrayfun in performance-critical paths (arrayfun is convenient, not always fast).

Interview Relevance

Medium–high: "what is a function handle?", "what does an anonymous function capture?", "how do you pass a function to fzero/ode45?", "arrayfun vs cellfun?".

Practice Questions

Create f = @(x, y) x.^2 + y.^2 and evaluate it on a meshgrid.

Use cellfun to find which names in a cell array start with 'B'.

Write a function apply_twice(f, x) that returns f(f(x)).

Build a cell array of handles {@sin, @cos, @tan} and evaluate each at pi/4.

Quick Quiz

Q1. (Multiple choice) @(x) x.^2 is: A) A string B) A function handle to an anonymous function C) A cell D) A struct Answer: B.

Q2. (Predict the output) g = 9.81; f = @(t) 0.5*g*t^2; g = 1.62; f(2)

Answer: 19.62 — g was captured as 9.81 (verified).

Q3. (True/False) cellfun(@upper, {'a','bc'}) works without extra options.

Answer: False. The outputs aren't scalars; use 'UniformOutput', false.

Q4. (Find the bug) f = @(x) x^2; f([1 2 3]) errors.

Answer: x^2 is a matrix power; use x.^2.

Coding Challenge

Write a function-handle-based numerical derivative d = @(f, x, h) (f(x + h) - f(x - h)) / (2*h) and use it to approximate the derivative of exp and sin at 1, comparing with the exact values.

d = @(f, x, h) (f(x + h) - f(x - h)) / (2 * h);
fprintf('d/dx exp at 1: %.8f (exact %.8f)\n', d(@exp, 1, 1e-5), exp(1))
fprintf('d/dx sin at 1: %.8f (exact %.8f)\n', d(@sin, 1, 1e-5), cos(1))