# Defer and Cleanup

### Defer and Cleanup

Many programs need to clean something up after using it.

A program may need to:

close a file

free memory

unlock a mutex

restore a setting

print a final message before leaving a scope

Zig gives you `defer` for this.

`defer` means: run this statement when the current scope ends.

#### A First Example

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

pub fn main() void {
    std.debug.print("first\n", .{});

    defer std.debug.print("third\n", .{});

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

This prints:

```text
first
second
third
```

The deferred statement is written before the second print:

```zig
defer std.debug.print("third\n", .{});
```

But it runs at the end of the scope.

The current scope here is the body of `main`.

#### Scope Is the Key

`defer` runs when the scope ends.

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

pub fn main() void {
    std.debug.print("A\n", .{});

    {
        defer std.debug.print("C\n", .{});
        std.debug.print("B\n", .{});
    }

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

This prints:

```text
A
B
C
D
```

The `defer` is inside the inner block. It runs when that inner block ends, before the program reaches `D`.

This is important. `defer` does not always wait until the function ends. It waits until the scope where it was declared ends.

#### Why `defer` Exists

Without `defer`, cleanup code is easy to forget.

Suppose you allocate memory:

```zig
const buffer = try allocator.alloc(u8, 1024);
```

Later, you need to free it:

```zig
allocator.free(buffer);
```

The problem is that the function may have many exits.

```zig
fn work(allocator: std.mem.Allocator) !void {
    const buffer = try allocator.alloc(u8, 1024);

    if (someCondition()) {
        allocator.free(buffer);
        return;
    }

    if (try somethingFails()) {
        allocator.free(buffer);
        return;
    }

    allocator.free(buffer);
}
```

This style is fragile. Every exit path must remember cleanup.

With `defer`, cleanup is placed next to the resource acquisition:

```zig
fn work(allocator: std.mem.Allocator) !void {
    const buffer = try allocator.alloc(u8, 1024);
    defer allocator.free(buffer);

    // use buffer
}
```

Now `buffer` is freed when the function scope ends.

This is cleaner because the allocation and cleanup are close together.

#### `defer` Runs on Early Return

`defer` still runs when a function returns early.

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

fn example(x: u8) void {
    defer std.debug.print("cleanup\n", .{});

    if (x == 0) {
        std.debug.print("early return\n", .{});
        return;
    }

    std.debug.print("normal return\n", .{});
}

pub fn main() void {
    example(0);
}
```

This prints:

```text
early return
cleanup
```

The function returns early, but the deferred statement still runs.

That is the main reason `defer` is useful. It protects cleanup from early exits.

#### Multiple `defer` Statements

You can have more than one `defer`.

They run in reverse order.

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

pub fn main() void {
    defer std.debug.print("one\n", .{});
    defer std.debug.print("two\n", .{});
    defer std.debug.print("three\n", .{});
}
```

This prints:

```text
three
two
one
```

The last deferred statement runs first.

This is deliberate. Cleanup usually needs to happen in the opposite order of setup.

Example:

```zig
setupA();
setupB();
setupC();

cleanupC();
cleanupB();
cleanupA();
```

`defer` naturally matches this pattern:

```zig
setupA();
defer cleanupA();

setupB();
defer cleanupB();

setupC();
defer cleanupC();
```

When the scope ends, cleanup happens as:

```text
cleanupC
cleanupB
cleanupA
```

#### Practical Example: Freeing Memory

Here is a common pattern:

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

fn makeMessage(allocator: std.mem.Allocator) !void {
    const message = try allocator.dupe(u8, "hello");
    defer allocator.free(message);

    std.debug.print("{s}\n", .{message});
}

pub fn main() !void {
    var gpa = std.heap.DebugAllocator(.{}){};
    defer _ = gpa.deinit();

    const allocator = gpa.allocator();

    try makeMessage(allocator);
}
```

The important part is:

```zig
const message = try allocator.dupe(u8, "hello");
defer allocator.free(message);
```

The memory is allocated, then cleanup is registered immediately.

When `makeMessage` ends, the memory is freed.

#### Practical Example: Closing a File

Files also need cleanup.

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

pub fn main() !void {
    const file = try std.fs.cwd().openFile("notes.txt", .{});
    defer file.close();

    // use file here
}
```

The file is opened here:

```zig
const file = try std.fs.cwd().openFile("notes.txt", .{});
```

The file is closed here:

```zig
defer file.close();
```

Even if later code returns early with an error, the file is still closed.

#### `defer` Captures Variables by Reference

A deferred statement uses the variable when the defer runs, not when it is declared.

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

pub fn main() void {
    var x: u8 = 1;

    defer std.debug.print("x = {}\n", .{x});

    x = 2;
}
```

This prints:

```text
x = 2
```

The `defer` runs at the end of the scope, after `x` has changed.

This matters when deferred code depends on mutable variables.

If you need to preserve the current value, copy it into a constant first:

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

pub fn main() void {
    var x: u8 = 1;
    const saved = x;

    defer std.debug.print("saved = {}\n", .{saved});

    x = 2;
}
```

This prints:

```text
saved = 1
```

#### `defer` with Blocks

You can defer a block.

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

pub fn main() void {
    defer {
        std.debug.print("cleanup step 1\n", .{});
        std.debug.print("cleanup step 2\n", .{});
    }

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

This prints:

```text
working
cleanup step 1
cleanup step 2
```

Use a deferred block when cleanup needs several statements.

#### `defer` Is Not an Error Handler

`defer` always runs when the scope exits.

It does not care whether the scope exits successfully or because of an error.

```zig
fn work() !void {
    defer cleanup();

    try step1();
    try step2();
}
```

If `step1` fails, `cleanup()` runs.

If `step2` fails, `cleanup()` runs.

If both steps succeed, `cleanup()` still runs.

This is useful for resources that must always be released.

For cleanup that should happen only on error, Zig has `errdefer`. That belongs to the error handling chapter, but here is the basic idea:

```zig
const resource = try createResource();
errdefer destroyResource(resource);
```

`errdefer` runs only if the scope exits with an error.

`defer` runs on every exit.

#### `defer` and Loops

A `defer` inside a loop runs at the end of the scope where it is declared.

If the loop body is the scope, the deferred statement runs at the end of each iteration.

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

pub fn main() void {
    for (0..3) |i| {
        defer std.debug.print("end iteration {}\n", .{i});
        std.debug.print("start iteration {}\n", .{i});
    }
}
```

This prints:

```text
start iteration 0
end iteration 0
start iteration 1
end iteration 1
start iteration 2
end iteration 2
```

Each loop iteration has its own block scope.

This is useful when each iteration acquires a temporary resource.

#### A Common Mistake

Do not put `defer` in a long loop if you expect cleanup to happen immediately but the scope does not end soon.

This is usually fine:

```zig
for (files) |path| {
    const file = try open(path);
    defer file.close();

    // use file
}
```

The loop body scope ends each iteration, so the file closes each iteration.

But if you put `defer` in an outer function scope while repeatedly allocating, cleanup may happen much later than intended.

The rule is simple: know which scope owns the `defer`.

#### Cleanup Should Be Close to Setup

This is a good style:

```zig
const buffer = try allocator.alloc(u8, 4096);
defer allocator.free(buffer);
```

The cleanup is directly below the allocation.

This is less clear:

```zig
const buffer = try allocator.alloc(u8, 4096);

// many lines later

defer allocator.free(buffer);
```

A reader should not need to search for cleanup.

Put `defer` immediately after the operation that creates the responsibility.

#### The Main Idea

`defer` schedules cleanup for the end of the current scope.

It runs on normal exit, early return, and error return.

Multiple deferred statements run in reverse order.

Use it when something must be undone:

```zig
const buffer = try allocator.alloc(u8, 1024);
defer allocator.free(buffer);
```

```zig
const file = try std.fs.cwd().openFile("notes.txt", .{});
defer file.close();
```

The beginner rule is simple: when you acquire a resource, write its cleanup immediately after it.

