5 ms·
It creates 2 disparate types of error handling that don't neatly mesh together. You have to handle error return values, but you also have to handle exceptions
by everforward 3y ago
It creates 2 disparate types of error handling that don't neatly mesh together. You have to handle error return values, but you also have to handle exceptions (panics) because they still exist.
My issue is mostly implementing both ways of bubbling up an error to somewhere it can be handled. I think having either error return values or exceptions is preferable to having both. I don't think exceptions are perfect, but if panic() absolutely has to exist then I'd rather have an entirely exception-based language than a language that uses both systems simultaneously.
E.g. if I write a function that accesses an element of an array without bounds-checking, it could panic and I have to handle that exception. Bounds-checking basically just becomes finding things that would throw exceptions and converting them to errors so we can pretend that exceptions don't exist.
- randomdata 3y ago> It creates 2 disparate types of error handling They are disparate conditions. Errors happen in response to conditions that occur during the execution of the application. Exceptions happen in response to conditions that occurred when the code was written. Very different things. It is highly unlikely that you want to handle an exception. It's the runtime equivalent of a compiler error. Do you also want to handle compiler errors so that your faulty code still compiles? Of course not, so why would you want to do the same when your coding mistakes are noticed at runtime? There are, uh, exceptions to that when it is necessary to handle exceptions, but if it you see it as routine you're doing something wrong. If you overloaded that with errors, forcing it to be routine, you'd have a nightmare on your hands (like in those other languages that have tried it).
- groestl 3y ago> Exceptions happen in response to conditions that occurred when the code was written. Huh? Stack overflow? Out of memory? > It is highly unlikely that you want to handle an exception It is very likely that I want to handle an exception. In fact, I want to handle all exceptions and keep my process and all other concurrent requests to it running. And don't tell me, that's not possible, because I've been doing that for decades. In Java that is.
- randomdata 3y ago> Stack overflow? Exception. The minimum available stack space is a known quantity. Exceeding it means you made a mistake. > Out of memory? Error. The available heap is typically not predictable. Your allocation function should provide an error state; and, indeed, malloc and friends do. > And don't tell me, that's not possible It is perfectly possible. Probably not a good idea, though, as you have proven that your code is fundamentally broken. Would you put your code in production if there was a way to ignore compiler failure?
- quaunaut 3y ago> Would you put your code in production if there was a way to ignore compiler failure? What compiler failure? Go literally does not warn you until it hits the error at runtime for these exceptions.
- randomdata 3y ago> What compiler failure? Pick something. I don't care. Let's say failure for reasons of having no return statement in a function that declares itself to return something. If you could flip a switch to see that code still compile somehow, knowing that the program is not correct, would you deploy it to production? > Go literally does not warn you until it hits the error at runtime for these exceptions. True, but only because the Go compiler isn't very smart. It trades having a simpler compiler for allowing some programmer faults to not be caught until runtime. But if there was such a thing as an ideal Go compiler, those exceptions would be caught at compile time. When it comes to exceptions, the fault is in the code itself, unlike errors where the fault is external to the program. Theoretically, those faults could be found before runtime. But it is a really hard problem to solve; hence why we accept exceptions as a practical tradeoff. We are just engineers at the end of the day.
- quaunaut 3y agoExcept we could just treat them the same, and we could have a type system that makes that possible. Multiple languages before Go had a solution to this, that could've been used. Or, it could've written said sufficiently advanced compiler itself. Instead, they didn't. And we all suffer for it.
- troupo 3y ago> Errors happen in response to conditions that occur during the execution of the application. Exceptions happen in response to conditions that occurred when the code was written. wat. You have code that ends up dividing by zero, and boom, you have an exception while the app is running. > It is highly unlikely that you want to handle an exception. You always want to handle an exception. That is how actual resilient systems are written
- troupo 3y agoGot downvoted. Do read Joe Armstrong's Making reliable distributed systems in the presence of software errors https://erlang.org/download/armstrong_thesis_2003.pdf https://erlang.org/download/armstrong_thesis_2003.pdf
- randomdata 3y ago> You have code that ends up dividing by zero, and boom, you have an exception while the app is running. Yes, and? That problem arose when the code was written. There is no reason why a program should ever find itself in a state where division by zero can occur. A simple if statement is all it takes to avoid that. If you see a divide by zero exception, the developer fucked up; having wrote an incorrect program. That's entirely different to, say, a hard drive crash causing writes to fail. Not even an ideal programmer writing an ideal piece of software completely void of all defects can avoid an error condition. > You always want to handle an exception. No. You always want to ensure that you have no exceptions in the first place. They are the runtime equivalent of compiler errors. If you encounter an exception in your software, you screwed up. There are circumstances where handling exceptions is warranted, but if you are routinely handling exceptions throughout your development, something is amiss.
- Gibbon1 3y agoOnce you get outside webshit you have a world where things need to be able to get the job done even in the presence of software bugs. And software bugs are just another type of failure. Some of those involve cases where failure is expensive or life threatening.
- abtinf 3y agoI cannot conceive of the scenario where it makes sense to recover a bounds-checking induced panic. The process should crash; the alternative is to continue operating in an unknown, irrecoverable, and potentially security compromised state.
- steveklabnik 3y agoRust shares Go's "errors as values + panics" philosophy. Rust also has a standard library API for catching panics. Its addition was controversial, but there are two major cases that were specifically enumerated as reasons to add this API: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md https://github.com/rust-lang/rfcs/blob/master/text/1236-stab... > It is currently defined as undefined behavior to have a Rust program panic across an FFI boundary. For example if C calls into Rust and Rust panics, then this is undefined behavior. Being able to catch a panic will allow writing C APIs in Rust that do not risk aborting the process they are embedded into. > Abstractions like thread pools want to catch the panics of tasks being run instead of having the thread torn down (and having to spawn a new thread). The latter has a few other similar examples, like say, a web server that wants to protect against user code bringing the entire system down. That said, for various reasons, you don't see catch_unwind used in Rust very often. These are very limited cases.
- everforward 3y ago> I cannot conceive of the scenario where it makes sense to recover a bounds-checking induced panic. A bog-standard HTTP server (or likely any kind of request-serving daemon). If a client causes a bounds-checking panic, I do not want that to crash the entire server. It's not even really particular to bounds-checking. If I push a change that causes a nil pointer dereference on a particular handler, I would vastly prefer that it 500's those specific requests rather than crashing the entire server every time it happens. The Go HTTP server does this internally (though there is talk about not doing it, deferred til Go 2 https://github.com/golang/go/issues/5465 https://github.com/golang/go/issues/5465). > The process should crash; the alternative is to continue operating in an unknown, irrecoverable, and potentially security compromised state. The goroutine should probably crash, but that doesn't necessarily imply that the entire program should crash. For some applications the process and the goroutine are one and the same, but that's not universally true. A lot of applications have some kind of request scope where it's desirable to be able to crash the thread a request is running on without crashing the entire server.
- the_gipsy 3y agoThere are two types of errors and Java's mistake was making them all the same.
- rowls66 3y agoThat’s not true. Java has 2 types of exceptions checked and unchecked. Checked exceptions are what this thread has been calling errors, and unchecked exceptions are what this thread has been calling exceptions. Maybe it was a mistake to call them both exceptions, but Java also has 2 types of errors.
- randomdata 3y agoI'd say Java named them appropriately. While you are right that they almost cover the same intent, error state is not dependent, whereas checked exceptions force a dependency on the caller[1]. They are not quite the same thing. [1] Ish. If we are to be pedantic, technically checked exceptions are checked by the exception handlers, not the exceptions themselves. If you return a 'checked' exception rather than throw it, Java won't notice. However, I expect for the purposes of discussion we are including exception handlers under the exception umbrella.
- the_gipsy 3y agoChecked exceptions are NOT like errors-as-values. It's only resemblance is that checked strictly forces the exception to be handled, similar to errors-as-values. But the handling itself is still the same as regular exceptions: out-of-band and not composable with anything else.