• FizzyOrange@programming.dev
    link
    fedilink
    arrow-up
    49
    arrow-down
    5
    ·
    3 months ago

    I think I disagree with everything here.

    Exceptions Are Much Easier to Work With

    Well, they’re “easier” in the same way that dynamic typing is easier. It’s obviously less work initially just to say “screw it; any error gets caught in main()”. But that’s short term easiness. In the long term its much more painful because:

    1. You don’t know which functions might produce errors, and therefore you don’t know where you should be even trying to handle errors. (Checked exceptions are the answer here but they are relatively rarely used in practice.)
    2. Actually handling errors properly often involves responding to errors from individual function calls - at least adding human readable context to them. That is stupidly tedious with exceptions. Every line turns into 5. Sometime it makes the code extremely awkward:
    try {
       int& foo = bar();
    } catch (...) {
       std::cout << "bar failed, try ...\n";
       return nullopt;
    }
    foo = 5;
    

    (It actually gets worse than that but I can’t think of a good example.)

    Over 100× less code! [fewer exception catching in their C++ database than error handling in a Go database]

    Well… I’m guessing your codebase is a lot smaller than the other one for a start, and you’re comparing with Go which is kind of worst case… But anyway this kind of proves my point! You only actually have proper error handling in 140 places - apparently mostly in tests. In other words you just throw all exceptions to main().

    System errors [he’s mainly talking about OOM, stack overflow & arithmetic errors like integer overflow]

    Kind of a fair point I guess. I dunno how you can reasonably stack overflows without exceptions. But guess what - Rust does have panic!() for that, and you can catch panics. I’d say that’s one of the few reasonable cases to use catch_unwind.

    Exceptions Lead to Better Error Messages

    Hahahahahaha. I dunno if a bare stack trace with NullPointerException counts as a “better error message”. Ridiculous.

    Exceptions Are More Performant

    Sure maybe in error handling microbenchmarks, or particularly extreme examples. In real world code it clearly makes little difference. Certainly not enough to choose an inferior error handling system.

    I would say one real reason to prefer exceptions over Result<>s is they are a fair bit easier to debug because you can just break on throw. That’s tricky with Result<> because creating a Err is not necessarily an error. At least I have not found a way to “break on Err”. You can break on unwrap() but that is usually after the stack has been unwound quite a bit and you lose all context.

    • BehindTheBarrier@programming.dev
      link
      fedilink
      English
      arrow-up
      4
      arrow-down
      1
      ·
      3 months ago

      It can be pretty convenient to throw an error and be done with it. I think for some languages like Python, that is pretty much a prefered way to deal with things.

      But the entire point of Rust and Result is as you say, to handle the places were things go wrong. To force you to make a choice of what should happen in the error path. It both forces you to see problems you may not be aware of, and handle issues in ways that may not stop the entire execution of your function. And after handling the Result in those cases, you know that beyond that point you are always in a good state. Like most things in Rust, that may involve making decisions about using Result and Option in your structs/functions, and designing your program in ways that force correct use… but that a now problem instead of a later problem when it comes up during runtime.

      • kersplomp@programming.dev
        link
        fedilink
        arrow-up
        3
        ·
        3 months ago

        But the entire point of Rust and Result is… to force you to make a choice of what should happen

        Checked exceptions also force you to handle it and take way less boilerplate.

        • BehindTheBarrier@programming.dev
          link
          fedilink
          arrow-up
          3
          arrow-down
          1
          ·
          edit-2
          3 months ago

          But nothing is forcing you to check exeptions in most languages, right?

          While not checking for exceptions and .unwrap() are pretty much the same, the first one is something you get by not doing anything extra while the latter is entirely a choice that has to be made. I think that is what makes the difference, and in similar ways why for example nullable enabled project in C# is desired over one that is not. You HAVE to check for null, or you can CHOOSE to assume it is not by trying to use the value directly. To me it makes a difference that we can accidentally forget about a possible exception or if we can choose to ignore it. Because problems dealt with early at compile time, are generally better than those that happen at runtime.

          • kersplomp@programming.dev
            link
            fedilink
            arrow-up
            2
            arrow-down
            1
            ·
            3 months ago

            I see your concern, but in practice that’s not what happens in languages like Java and Python with exceptions. Not checking for exceptions is a choice because everyone knows you need to check in your top-level functions. Forgetting to catch is a problem that only hits newbies.

            • OmnipotentEntity@beehaw.org
              link
              fedilink
              arrow-up
              5
              arrow-down
              1
              ·
              3 months ago

              A problem that only affects newbies huh?

              Let’s say that you are writing code intended to be deployed headless in the field, and it should not be allowed to exit in an uncontrolled fashion because there are communications that need to happen with hardware to safely shut them down. You’re making a autonomous robot or something.

              Using python for this task isn’t too out of left field, because one of the major languages of ROS is python, and it’s the most common one.

              Which of the following python standard library functions can throw, and what do they throw?

              bytes, hasattr, len, super, zip

    • BatmanAoD@programming.dev
      link
      fedilink
      arrow-up
      2
      arrow-down
      1
      ·
      3 months ago

      There’s also a massive tradeoff for when the error condition actually occurs. If an exception does get thrown and caught, that is comparatively slowwww.

      • UndercoverUlrikHD@programming.dev
        link
        fedilink
        arrow-up
        2
        ·
        3 months ago

        The author pointed out how exceptions are often faster than checking every value. If your functions throws an error often enough that Exception handling noticeably slow down your program, surely you got to take a second look at what you’re doing.

        • BatmanAoD@programming.dev
          link
          fedilink
          arrow-up
          1
          ·
          3 months ago

          It depends what kind of errors you’re talking about. Suppose you’re implementing retries in a network protocol. You can get errors pretty regularly, and the error handling will be a nontrivial amount of your runtime.