# Idiom for an "old-school" try-catch block

**URL:** <https://ziggit.dev/t/idiom-for-an-old-school-try-catch-block/3821>\
**Category:** Help\
**Tags:** language\
**Created:** [April 4, 2024, 1:48am UTC](https://ziggit.dev/t/idiom-for-an-old-school-try-catch-block/3821 "2024-04-04T01:48:33Z")\
**Posts on this page:** 1\
**Showing post:** 2

<div class="post-metadata">

**Author:** ![AndrewCodeDev](https://ziggit.dev/letter_avatar_proxy/v4/letter/a/278dde/32.png) [@AndrewCodeDev](https://ziggit.dev/u/AndrewCodeDev)\
**Post date:** [April 4, 2024, 2:07am UTC](https://ziggit.dev/t/idiom-for-an-old-school-try-catch-block/3821/2 "2024-04-04T02:07:27Z")

</div>

Edited - added third pattern.

Three patterns for ya… first two are breaking blocks:

In this example, we break the value back to the `result` if it’s an error or a value. We can inspect or use it either way.

```zig
pub fn main() !void {

    const result = blk: {
        // break will return an error here
        const out = bar(42, 42) catch |e| break :blk e;

        // break will return the result
        break :blk out;
    };

    // unpack the error (can use if/else and switch for this too)
    const out = result catch |e| {
        return std.debug.print("caught an error: {}", .{e});
    };

    std.debug.print("Out: {}", .{ out });
}

```

The error can also be discarded with a raw break.

```zig
pub fn main() !void {

    blk: {
        const out = foo(42, 42) catch break :blk;
        // the happy path...
        std.log.info("Result: {}", .{out});        
    }
    // the not-so-happy path...
    std.log.info("Something bad happened.", .{});
}

```

This is closer to the canonical `try/catch` that you’re talking about. You break the block in the same way you’d use a `throw`. The obvious issue with the second one is you lose whatever error you had. It’s really up to you if you care about that or not.

Another pattern to consider is `try/catch |...| return ...` and `catch |...| switch (...)`:

```zig
const MyError = error { A, B, C };

pub fn foo(_: i32, _: i32) MyError!i32 {
    return MyError.A;
}

pub fn bar(_: i32, _: i32) MyError!i32 {
    return MyError.B;
}
pub fn baz(x: i32, y: i32) MyError!i32 {
    // try works as a short hand here
    const u = try foo(x, y);
    // more verbose but can be further customized
    const v = bar(u, x) catch |e| return e;
    return v;
}

pub fn main() !void {

    const out: i32 = baz(42, 42) catch |e| switch (e) {
        MyError.A => return std.log.err("Handle Error A.", .{}),
        MyError.B => return std.log.err("Handle Error B.", .{}),
        MyError.C => return std.log.err("Handle Error C.", .{}),
    };

    std.log.info("Result: {}", .{out});
}

```

This pattern forces the error to go upstream to the call site so you will end up doing your error handling in one place. You’ll notice in the `switch` block, I’m doing returns because out will be considered `void` and we have to evacuate the function if an error occurs.

We had a long discussion about these: [What is the best way to handle unrecoverable errors like OutOfMemory in an application?](https://ziggit.dev/t/what-is-the-best-way-to-handle-unrecoverable-errors-like-outofmemory-in-an-application/3009)

And that was based on this thread: [Zig Code Smells](https://ziggit.dev/t/zig-code-smells/2928/)

---

_[View the full topic](https://ziggit.dev/t/idiom-for-an-old-school-try-catch-block/3821)._
