# `catch`

### `catch`

`catch` handles an error union.

Where `try` passes an error to the caller, `catch` deals with it in the current expression.

```zig
const n = parseDigit('x') catch 0;
```

If `parseDigit('x')` succeeds, `n` receives the digit. If it fails, `n` receives `0`.

A complete example:

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

fn parseDigit(c: u8) !u8 {
    if (c < '0' or c > '9') {
        return error.InvalidDigit;
    }

    return c - '0';
}

pub fn main() void {
    const a = parseDigit('8') catch 0;
    const b = parseDigit('x') catch 0;

    std.debug.print("{d} {d}\n", .{ a, b });
}
```

The output is:

```text
8 0
```

The right side of `catch` must produce the same final type as the successful value. Here the successful value is `u8`, and the fallback value `0` can be used as a `u8`.

`catch` may also bind the error:

```zig
const n = parseDigit('x') catch |err| {
    std.debug.print("error: {}\n", .{err});
    return;
};
```

The name `err` is available only inside the block after `catch`.

A common use is to translate one error into another:

```zig
fn readConfig() ![]const u8 {
    return readFile("config.txt") catch |err| switch (err) {
        error.FileNotFound => error.MissingConfig,
        else => err,
    };
}
```

This says: if the file is missing, return a program-level error. For all other failures, return the original error.

`catch` is an expression. It can return a value:

```zig
const value = parseDigit(c) catch 0;
```

or it can leave the function:

```zig
const value = parseDigit(c) catch |err| return err;
```

That second form is exactly what `try` abbreviates.

So this:

```zig
const value = try parseDigit(c);
```

means:

```zig
const value = parseDigit(c) catch |err| return err;
```

Use `catch` when the local code has a policy.

Examples of local policy:

```zig
const port = parsePort(text) catch 8080;
```

```zig
const file = openLogFile() catch {
    std.debug.print("log file unavailable\n", .{});
    return;
};
```

```zig
const user = findUser(id) catch |err| switch (err) {
    error.NotFound => return null,
    else => return err,
};
```

`catch` should not hide real failure by accident. A fallback value is good only when it is truly acceptable.

This is usually bad:

```zig
const bytes = readFile(path) catch "";
```

An empty file and a failed read are different facts. Code that treats them as the same will lose information.

Prefer this:

```zig
const bytes = readFile(path) catch |err| {
    std.debug.print("cannot read file: {}\n", .{err});
    return err;
};
```

or this:

```zig
const bytes = try readFile(path);
```

A `catch` block may contain several statements:

```zig
const n = parseDigit(c) catch |err| {
    std.debug.print("bad digit: {}\n", .{err});
    return error.BadInput;
};
```

The block returns `error.BadInput`, so the whole expression leaves the current function with that error.

`catch` is most useful at boundaries: command-line input, configuration loading, file access, network calls, and places where a program decides whether to recover, retry, substitute a default, or stop.

Inside ordinary helper functions, `try` is usually better. It keeps the error visible and lets a higher layer decide what the error means.

Exercise 8-17. Write `parseDigitOrNine` using `catch`.

Exercise 8-18. Write a function that converts `error.FileNotFound` into `error.MissingInput`.

Exercise 8-19. Write a program that tries to parse a digit and prints a message when parsing fails.

Exercise 8-20. Find a place where `catch 0` would be wrong. Explain why.

