Hacker News new | ask | show | jobs
by fluoridation 3 days ago
>If I am choosing to change the API contract then someone who wants to use the new API has to update. This is not a big deal.

Throwing lets you handle the new situation without changing the API at all.

>Let me be clear. Having to add a bunch of random fucking try-catch bullshit around every fucking function call is EXACTLY why I hate exceptions and is EXACTLY what I think is bad software design.

See, that's what happens when you form your opinions on half-digested ideas. Let me be clear. You don't add "a bunch" of try-catch blocks. You don't wrap every call that's capable of failing exceptionally in a try-catch block. That's exactly how you don't use exceptions. The whole point of exceptions is that the compiler will handle the stack unwinding for you so you don't need to worry about it. If you don't want to, or don't know how, or can't handle an exception at a specific point then don't. Let it bubble up for someone else to catch. See the ellipsis in my example? Inside of it you might have a gigantic call tree that performs all sorts of different operations that may all fail in different and unexpected ways. You could write the whole thing and not have a single try-catch besides the one I wrote explicitly. Let me reiterate; this is what you DON'T do:

  try{
    foo();
  }catch (...){
    return Error1;
  }
  try{
    bar();
  }catch (...){
    return Error2;
  }
  try{
    baz();
  }catch (...){
    return Error3;
  }
The only reason you would do something like this is to satisfy a specification such that you have to return different errors, specifically when each of the different calls fails. So... don't specify your functions such that you're required to do this? Just do

  foo();
  bar();
  baz();
or if you really must not throw from the function,

  try{
    foo();
    bar();
    baz();
  }catch (...){
    return SomethingFailed;
  }
TL;DR: Instead of bitching about exceptions, learn how to use them properly.
1 comments

> Throwing lets you handle the new situation without changing the API at all.

I do not disagree. https://xkcd.com/1172/

If you add exceptions to a library that didn’t previously use them then I almost definitely have to update my code. The fact that it compiles and runs but will behave in undesirable ways makes it even worse, not better!

> or if you really must not throw from the function,

I’m aware.

But if your library that offers foo adds exceptions now I need to think about it at every single callsite, and probably wrap the function. It’s extremely irritating.

> learn how to use them properly.

In my 20+ years of professional C++ development I have a great experience not using exceptions and a strictly negative experience using them.

Perhaps sometimes I’ll stumble upon a library or codebase where exceptions make the code simpler, easier to understand, and easier to write. But my experience is exceptions make everything strictly worse and that not using exception is a strict win with zero downsides.

>The fact that it compiles and runs but will behave in undesirable ways makes it even worse, not better!

* Exceptions

* Unstable API

* Incorrect behavior

Pick your poison. I know what I prefer.

>But if your library that offers foo adds exceptions now I need to think about it at every single callsite

You really don't. Like I said, it's kind of the whole point of exceptions.

>In my 20+ years of professional C++ development I have a great experience not using exceptions and a strictly negative experience using them.

Hence my recommendation to learn how to use them. I can replace "exceptions" with anything else (computers, diesel engines, HR people), and there's probably someone who holds that belief. That doesn't make it true.

And GTFO with that No True Scotsman nonsense. That a tool can be misused doesn't delegitimize the tool. If you saw someone using classes instead of namespaces you wouldn't conclude classes are bad, you'd call that person a knobhead.

> You really don't. Like I said, it's kind of the whole point of exceptions.

No, this is actually just wrong. With exceptions you “don’t have to think about” the exception getting caught by some higher level catch.

But you do have to think about it in the sense that every single line in your code could unwind. Which makes ensuring you remain in a valid state more difficult.

One of the issues with exceptions isn’t the throw. It’s what do you do after you catch.

> That a tool can be misused doesn't delegitimize the tool.

I’m always open to the possibility that if something I’ve seen has been bad 100 times then on the 101st it might be good. But at some point you really just have to call a spade a spade.

>But you do have to think about it in the sense that every single line in your code could unwind.

No, this is actually just wrong. There is code that can throw, and there is code that cannot possibly throw. The way you write exception-safe code is by not holding manually-managed resources (e.g. raw pointers that own heap allocations, or file descriptors that must be close()d, or anything else that needs cleanup code that has not been put in a destructor) during sections that may throw. In other words, use RAII to manage your resources, regardless of whether exceptions may be thrown.

Program state is significantly more complex than just needing some RAII resources to cleanup via destructors.

> during sections that may throw

Yeah one of the problems with exceptions is it’s impossible to know what “may throw” other than “well I guess literally anything so everything”. It is very irritating.

At the end of the day exceptions are just a little syntactic sugar. Or perhaps syntactic bitters.

It is notable that systems languages designed after C++ all chose to not include exceptions. Go, Zig, Swift, Odin, Jai.

Rust panics are kinda sorta exceptions in that they unwind. But their intended use case is for irrecoverable errors. And of course you can set panic=abort.

C++ exceptions are very rarely treated as so serious module level irrecoverability.

>Program state is significantly more complex than just needing some RAII resources to cleanup via destructors.

You're being rather vague. All throwing does is cause control flow to jump to the nearest catch that can handle the exception, destructing all objects along the way. I struggle to think of an example that could cause problems that isn't some variation of "I had some code after the exception that I needed to run, and it didn't run, because it wasn't set up to run at scope exit". I'd love to see such an example if you have one.

>it’s impossible to know what “may throw”

* If it's a throw statement, it may throw.

* If it's an expression that contains a 'new' operator, it may throw.

* If it's an expression that contains a dynamic_cast to a reference type, it may throw.

* If it calls a function that you don't know that it does not do any of the above, it may throw.

* If it's unknown if a function is called (e.g. types are templated), it may throw.

* Otherwise, it doesn't throw.

If you're managing resources manually, either make sure not to call any functions until you release them, or stop managing them manually. I encourage the latter.

> If you add exceptions to a library that didn’t previously use them then I almost definitely have to update my code.

No, that's the whole point. You let them bubble up to the top of the event loop and you report the error to the user. As a user, anything else leads to shitty software where the programmer tries to outsmart the world around them (and fails, obviously, leading to worse end-user experience than just admitting that you don't and can't have control over everything)

What user? I work on systems where there might not be a keyboard or a mouse or a display and where the use of there is one doesn’t care that the “flooblutz was out of turving.” The only thing stack unwinding gets me is it forces me to restart my program from the beginning.
^^^ truth speaker
Addendum: I, for one, have used software that would constantly show exception-related error message dialogs.

Hell, I'm forced to use such software at work because we're (at least for now) stuck with a horrible legacy vendor.

It is not fun. So, no, "just show it to the userand let them decide" doesn't actuality resolve anything either.