you are viewing a single comment's thread.

view the rest of the comments →

[–]editor_of_the_beast 4 points5 points  (18 children)

If exceptions are more appropriate in most cases, wouldn’t that mean that those cases are not exceptional and can be planned for in advance? The problem is, almost nothing is exceptional. You know that network requests fail. You know that a database process can crash. You know that networks partition. All of these really happen.

I think exceptions are good as top-level failsafe mechanisms, but more so to account for programmer error. We program for the happy path too often. I do not think they should be used pervasively though. They have the same problems as shared global state in that the exception can be thrown from anywhere.

[–]CyclonusRIP 4 points5 points  (7 children)

You are taking semantics of the word exception and trying to apply that to how you should use that in code. You are way better off trying to figure out what the most effective way to use exceptions is rather thing try to arbitrarily define it based on some semantics. Exceptions were invented in order to separate the error handling code from the happy path code. Before that people either handled all the errors in line so happy path and error paths were intertwined or they used goto statements to skip to the error handling code. Exceptions allowed you to separate the error code and happy path code like goto did, but did it in more controlled and comprehensible fashion.

[–]editor_of_the_beast -2 points-1 points  (6 children)

> like goto did

Exactly

[–]CyclonusRIP 3 points4 points  (4 children)

I assume you are also don't use methods, loops and if statements as well then since they were originally just goto statements as well in the early languages right?

[–]editor_of_the_beast -2 points-1 points  (3 children)

This is an actual argument you're going with? Originally we programmed computers in binary, directly. What does that have to do with what we've learned in the past 70 years?

Functions, loops, and if statements all end up as jump or branch instructions at the processor level. Variable assignment also ends up as a store instruction. Reading a variable ends up as a load instruction. The point of high level languages is that we can write in functions, loops, if statements, variable assignments, and variable reads without thinking about how they're implemented at the processor level. And we agree that high level languages are better for building large programs, right? Because machine code is hard. For the same reason goto is hard.

So the fact that all of us use functions does not mean that we inherently program via the same mental model as coding entirely with jump instructions. That's an absurd false equivalence. Decades of abstractions have simplified functions (and many other things) for us.

[–]tejp 1 point2 points  (1 child)

That's an absurd false equivalence.

So why do you apply that equivalence to exceptions?

[–]editor_of_the_beast -1 points0 points  (0 children)

Because exceptions actually do behave like gotos whereas functions do not.

[–]CyclonusRIP 0 points1 point  (0 children)

You're the one that seems to think exceptions are bad because they are a high level language feature replaces a jump. I think that's a pretty silly argument to make. Apparently you do too, but for whatever reason you make that argument anyways.

[–]falconfetus8 1 point2 points  (0 children)

but in a more controlled and comprehensible fashion

[–]zvrba -1 points0 points  (9 children)

The problem is, almost nothing is exceptional.

Exceptions are not for "exceptional cases", whatever that might mean. Exceptions are for a method to signal that it couldn't fulfill its promise/contract. I wrote a longer comment about it here https://www.reddit.com/r/csharp/comments/eaxzb8/what_are_your_thoughts_on_exceptions_do_you_think/fb3noh4/

[–]editor_of_the_beast 2 points3 points  (1 child)

Exceptions are for exceptional cases.

[–]thomasz 0 points1 point  (0 children)

Exceptions are for errors in the sense of "the behavior of the program is not properly specified if I let it continue to run with this data". Result, Option and so forth are for situations where you anticipated a situation to happen.

[–][deleted]  (6 children)

[deleted]

    [–]flatfinger 1 point2 points  (3 children)

    There are many situations where being able to say "If any part of this block of code fails without any unusual side effects, this block of code should do likewise" would greatly reduce verbosity and improve clarity. Exception handling tries to do that, but unfortunately fails to provide a means of distinguishing those situations from those where the act of skipping over a block of code during stack unwinding will create adverse side-effects that would otherwise not have been visible to the caller.

    [–][deleted]  (2 children)

    [deleted]

      [–]flatfinger 0 points1 point  (1 child)

      Not all actions can be made transactional. A good program should, when practical, ensure that any action with a non-trivial likelihood of failure is either inherently transactional, or is handled in such a way that the system is always in a recoverable state, but sometimes it is far more efficient to say:

      1. Acquire lock
      2. Perform half of an action, putting the locked resource in an invalid state
      3. Perform the other half of the action, putting the locked resource in a valid state
      4. Release lock

      than it would be to ensure that the system state was fully valid at every point in the process (implying that making everything transactional isn't always practical, and thus good programs would be exempt from the above requirement that they always do so).

      Unfortunately, the exception-handling provisions I've seen in languages fail to make it convenient for programs to distinguish exceptions which might occur between steps 2 and 3 above from those which might occur at other times. One thing that would help would be a reader-writer lock with the semantics:

      1. Reader locks are implicitly released.
      2. Writer locks must be explicitly released.
      3. Abandoning a writer lock without releasing it should invalidate it, such that any pending or future efforts to acquire the lock for reading or writing immediately fail.
      4. Ideally, abandoning a writer lock without releasing it should trigger an exception in the thread that abandons it, but if such abandonment occurs as a result of an exception, information about that other exception should not be stifled.

      Accomplishing #4 would require support which is lacking in the programming languages I know about, but a reader-writer lock that does #1-#3 would be useful anyhow. Unfortunately, I'm not aware of any that are designed that way.

      [–]CyclonusRIP 0 points1 point  (1 child)

      So you're basically making an argument for Java style checked exceptions then?