# `try`

### `try`

`try` is a shortcut for a common operation:

Call a function that may fail. If it succeeds, use the value. If it fails, return the error from the current function.

This function may fail:

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

    return c - '0';
}
```

The caller can use `try`:

```zig
fn parseTwoDigits(a: u8, b: u8) !u8 {
    const x = try parseDigit(a);
    const y = try parseDigit(b);

    return x * 10 + y;
}
```

This line:

```zig
const x = try parseDigit(a);
```

means roughly:

```zig
const x = parseDigit(a) catch |err| return err;
```

So `try` does not handle the error. It passes the error to the caller.

The current function must be able to return that error:

```zig
fn parseTwoDigits(a: u8, b: u8) !u8
```

The `!u8` return type says the function may return an error.

Here is the full program:

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

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

    return c - '0';
}

fn parseTwoDigits(a: u8, b: u8) !u8 {
    const x = try parseDigit(a);
    const y = try parseDigit(b);

    return x * 10 + y;
}

pub fn main() !void {
    const n = try parseTwoDigits('4', '2');
    std.debug.print("{d}\n", .{n});
}
```

The output is:

```text
42
```

Now change the call:

```zig
const n = try parseTwoDigits('4', 'x');
```

The first digit succeeds. The second digit fails. The error returned by `parseDigit` is returned by `parseTwoDigits`, then returned by `main`.

`try` makes this chain explicit in the type, but compact in the code.

Without `try`, the same function can be written with `catch`:

```zig
fn parseTwoDigits(a: u8, b: u8) !u8 {
    const x = parseDigit(a) catch |err| return err;
    const y = parseDigit(b) catch |err| return err;

    return x * 10 + y;
}
```

This is longer and usually no clearer.

Use `try` when the current function cannot do anything useful with the error.

Use `catch` when the current function can handle, replace, log, or recover from the error.

For example:

```zig
fn parseDigitOrZero(c: u8) u8 {
    return parseDigit(c) catch 0;
}
```

This function handles the error by returning a default value.

The return type is plain `u8`, not `!u8`, because no error escapes.

`try` works with any error union type:

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

If the file opens, `file` receives the opened file. If opening fails, the error is returned.

This pattern appears often:

```zig
const value = try operationThatMayFail();
```

Read it as:

> get the value, or leave this function with the error.

`try` can also be used inside expressions:

```zig
const result = (try parseDigit('7')) + 1;
```

The value unwrapped by `try` is a `u8`, so it can be used in arithmetic.

But keep such expressions simple. Error flow should be easy to see.

The main rule is this: `try` propagates. It does not recover.

Exercise 8-13. Rewrite a function that uses `catch |err| return err` so that it uses `try`.

Exercise 8-14. Write `parseThreeDigits` using `try`.

Exercise 8-15. Write `parseDigitOrZero` using `catch`.

Exercise 8-16. Open a file with `try`, then close it with `defer`.

