• balsoft@lemmy.ml
    link
    fedilink
    arrow-up
    4
    arrow-down
    12
    ·
    edit-2
    1 day ago

    Sadly there’s still no truly good way to handle errors in rust. TBH I’m not sure if we as an industry have figured out an efficient, foolproof, composable, not overly verbose way to handle errors, so it’s not entirely on Rust.

    • calcopiritus@lemmy.world
      link
      fedilink
      arrow-up
      3
      ·
      10 hours ago

      Rust allows you to choose whatever method you want.

      • Early return propagating the error
      • Early return ignoring the error (maybe by returning a default value)
      • Explicit handling by if-else (or match) to distinguish between error and not error cases.
      • Early return and turn the error into another type that is easier to handle by the caller.
      • Assume there is no error, and just panic if there is. (.unwrap)

      There are only 2 error handling methods that you cannot do:

      • Exceptions
      • Ignore the error and continue execution

      And that is because both of them are bad because they allow you to do the second one, when .unwrap is just there and better.

      If your concept of “not ugly” is “I just want to see the happy path” then you either write bad code that is “not ugly” or write good code that is “ugly”. Because there is no language that allows you to handle errors while not having error handling code near where the errors are produced.

      • balsoft@lemmy.ml
        link
        fedilink
        arrow-up
        1
        ·
        9 hours ago

        I am well aware, I wrote quite a lot of Rust, including professionally. I’m not necessarily talking about the “clear happy path”, even though that is relatively nice to have (Rust sort-of allows that with the ? sugar and the pseudo-functor and pseudo-monad methods on wrappers); I’m talking more about the fine line between the overly verbose lists of all the errors that a function could produce (thiserror-style) or just a single messy error type that makes error handling difficult (anyhow-style). There surely must be something in between there that is concise, type-safe, and composable, but I haven’t seen it in any language yet.

        • calcopiritus@lemmy.world
          link
          fedilink
          arrow-up
          2
          ·
          8 hours ago

          In my case, I don’t usually encounter cases where I can’t just ?. But when I do, just make an error enum (kinda like thiserror) that encapsulates the possible errors + possibly adds more.

          On the call site, just convert to string if I don’t care about specifics (anyhow-style).

          I don’t find this much painful.

          Concise: not much on the declaration side, since you have to create an entire enum for each function in worst-case scenario. But on code side, it’s just .map_err(MyError)?.

          Type-safe: can’t beat errors as enum values wrapped in Result.

          Composable: i don’t think you can beat rust enums in composability.

          I don’t use anyhow/thiserror, so I’m not sure. But I believe thiserror fixes the conciseness issue for this.

          • balsoft@lemmy.ml
            link
            fedilink
            arrow-up
            1
            ·
            8 hours ago

            thiserror helps a bit with conciseness. But it’s still the most annoying part of writing Rust for me, even more annoying than async closure capture semantics, and one that I happily offload to deepseek whenever I have to write it. I was even thinking of making some insane proc_macro that would traverse a function and extract the list of all ?, deduce the types, and come up with the final error type (maybe with some hints). But this turned out to be too difficult for a weekend project and ain’t nobody wants to pay me to write it.

            Type-safe: can’t beat errors as enum values wrapped in Result.

            I’m talking more about the anyhow-style here. It’s not very type-safe.

            Composable: i don’t think you can beat rust enums in composability.

            Well, thiserror-style enums are composable-ish, but they can be too structured for their own good. Sometimes you want only a particular property of an error (e.g. one of the HTTP requests returned 429 or something), and don’t care about the particular branch of the call tree it came from. Rust doesn’t really have the compile-time flexibility to write such a check without a ton of boilerplate that will also break once the call tree changes.

    • Ephera@lemmy.ml
      link
      fedilink
      English
      arrow-up
      2
      ·
      23 hours ago

      Yeah, I was gonna say, error handling easily makes up 80+% of the code paths, and depending on whether you’re building a library or service or script etc., different strategies are most suitable for how to deal with those code paths.

      In a script, you often just want it to crash. In a library, you want to make these code paths matchable, in case the user cares why something failed. And then you have the awkward in-between, which is that 99% of your application codebase will be used by your main-function like a library, but you don’t want to spend as much effort on error handling for that as a proper library does, in particular also because you know what all consumers of your application-library need to know.

      So, it’s kind of multiple different problems, with overlap, and people are hoping for one easy solution to cover all these problems.