# A First Example

### Function Pointers

Functions are values.

That means a function can be:

- stored
- passed to another function
- selected dynamically
- called indirectly

A function pointer stores the address of a function.

Instead of calling a function directly:

```zig
add(10, 20);
```

you can store the function in a variable and call it later.

This is called indirect function calling.

Function pointers are important in:

- callbacks
- event systems
- plugin systems
- virtual machines
- game engines
- operating systems
- schedulers
- interpreters

## A First Example

```zig
const std = @import("std");

fn add(a: i32, b: i32) i32 {
    return a + b;
}

pub fn main() void {
    const operation = add;

    const result = operation(10, 20);

    std.debug.print("{}\n", .{result});
}
```

Output:

```text
30
```

This line:

```zig
const operation = add;
```

stores the function in a variable.

Then:

```zig
operation(10, 20);
```

calls the function indirectly.

## Functions Have Types

Every function has a function type.

Example:

```zig
fn add(a: i32, b: i32) i32
```

This means:

- parameters:
  - `i32`
  - `i32`
- returns:
  - `i32`

A matching function pointer must use the same signature.

## Explicit Function Pointer Types

You can declare function pointer types explicitly.

Example:

```zig
const Operation = *const fn(i32, i32) i32;
```

Read this carefully:

| Part | Meaning |
|---|---|
| `*const` | pointer to immutable function |
| `fn(...)` | function type |
| `(i32, i32)` | parameter types |
| `i32` | return type |

Using it:

```zig
const std = @import("std");

const Operation = *const fn(i32, i32) i32;

fn add(a: i32, b: i32) i32 {
    return a + b;
}

pub fn main() void {
    const op: Operation = add;

    const result = op(5, 7);

    std.debug.print("{}\n", .{result});
}
```

Output:

```text
12
```

## Selecting Functions Dynamically

Function pointers allow runtime selection.

Example:

```zig
const std = @import("std");

fn add(a: i32, b: i32) i32 {
    return a + b;
}

fn subtract(a: i32, b: i32) i32 {
    return a - b;
}

pub fn main() void {
    const use_add = true;

    const op = if (use_add)
        add
    else
        subtract;

    const result = op(20, 5);

    std.debug.print("{}\n", .{result});
}
```

Output:

```text
25
```

Changing:

```zig
const use_add = false;
```

produces:

```text
15
```

The selected function changes dynamically.

## Passing Functions to Functions

Functions can receive function pointers as parameters.

Example:

```zig
const std = @import("std");

fn add(a: i32, b: i32) i32 {
    return a + b;
}

fn multiply(a: i32, b: i32) i32 {
    return a * b;
}

fn execute(
    op: *const fn(i32, i32) i32,
    a: i32,
    b: i32,
) i32 {
    return op(a, b);
}

pub fn main() void {
    const x = execute(add, 2, 3);
    const y = execute(multiply, 2, 3);

    std.debug.print("{} {}\n", .{ x, y });
}
```

Output:

```text
5 6
```

This is a callback pattern.

The caller supplies behavior.

## Callback Mental Model

Without callbacks:

```text
function decides behavior
```

With callbacks:

```text
caller provides behavior
```

This makes programs more flexible.

## Arrays of Function Pointers

You can store multiple functions together.

Example:

```zig
const std = @import("std");

fn add(a: i32, b: i32) i32 {
    return a + b;
}

fn subtract(a: i32, b: i32) i32 {
    return a - b;
}

fn multiply(a: i32, b: i32) i32 {
    return a * b;
}

pub fn main() void {
    const operations = [_]*const fn(i32, i32) i32{
        add,
        subtract,
        multiply,
    };

    for (operations) |op| {
        const result = op(10, 5);

        std.debug.print("{}\n", .{result});
    }
}
```

Output:

```text
15
5
50
```

This pattern appears in interpreters and dispatch systems.

## Dispatch Tables

Function pointer arrays are often called dispatch tables.

Conceptually:

```text
opcode -> function
```

Example:

```text
ADD -> addFunction
SUB -> subtractFunction
MUL -> multiplyFunction
```

Virtual machines frequently work this way.

## Function Pointers Inside Structs

Structs may contain function pointers.

Example:

```zig
const Handler = struct {
    callback: *const fn() void,
};
```

This allows objects to carry behavior.

Example usage:

```zig
const Button = struct {
    onClick: *const fn() void,
};
```

GUI systems often use this style.

## Returning Function Pointers

Functions may return function pointers.

Example:

```zig
fn choose(
    flag: bool,
) *const fn(i32, i32) i32 {
    if (flag) {
        return add;
    }

    return subtract;
}
```

This allows dynamic strategy selection.

## Anonymous Functions and Closures

Some languages support closures heavily.

Zig intentionally keeps things simpler.

Zig does not have full automatic closures like JavaScript or Python.

Instead, Zig prefers explicit data passing.

This reduces hidden allocations and hidden state.

## Compile-Time Function Selection

Zig often performs function selection at compile time.

Example:

```zig
fn process(comptime op: fn(i32, i32) i32) void {

}
```

This allows the compiler to optimize aggressively.

Compile-time polymorphism is one of Zig’s major strengths.

## Function Pointer Safety

Function pointers must match the correct signature.

Incorrect example:

```zig
fn hello() void {

}

const op: *const fn(i32, i32) i32 = hello;
```

Compiler error:

```text
function type mismatch
```

The compiler checks signatures strictly.

## Direct Calls vs Indirect Calls

Direct call:

```zig
add(1, 2);
```

Indirect call:

```zig
op(1, 2);
```

Indirect calls are slightly harder for CPUs to optimize because the exact target may not be known ahead of time.

Sometimes performance-critical systems avoid excessive indirect calls.

## Function Pointers in Real Systems

Function pointers are common in:

| System | Usage |
|---|---|
| GUI toolkits | button callbacks |
| Game engines | event handlers |
| Operating systems | interrupt tables |
| Interpreters | opcode dispatch |
| Networking | packet handlers |
| Databases | query execution |
| Plugins | dynamic behaviors |

They are one of the core building blocks of low-level software design.

## A Complete Example

```zig
const std = @import("std");

const Operation = *const fn(i32, i32) i32;

fn add(a: i32, b: i32) i32 {
    return a + b;
}

fn subtract(a: i32, b: i32) i32 {
    return a - b;
}

fn calculate(
    op: Operation,
    a: i32,
    b: i32,
) i32 {
    return op(a, b);
}

pub fn main() void {
    const operations = [_]Operation{
        add,
        subtract,
    };

    for (operations) |op| {
        const result = calculate(op, 20, 5);

        std.debug.print("{}\n", .{result});
    }
}
```

Output:

```text
25
15
```

This program demonstrates:

- storing functions
- passing functions
- indirect calls
- dispatch through arrays

These are foundational techniques in systems programming.

## Mental Model

A function pointer is:

```text
a variable that refers to executable code
```

Instead of storing ordinary data like integers or strings:

```text
42
"hello"
```

a function pointer stores:

```text
where a function lives in memory
```

This allows programs to choose behavior dynamically.

That flexibility is one reason function pointers are so important in low-level programming.

