Allowing unchecked exceptions in languages without explicit error handling or the return of error values is a mistake IMO! Makes it impossible to call a function safely
Exactly, C++ exceptions are horrible, you never know what throws what. Java made C++ exceptions better by making them explicit, so you always know what throws. Then Kotlin came and made everything a unusable mess (don't get me wrong, I love Kotlin, just hate that it doesn't have explicit exceptions).
I honestly think the best error handling strategy is employed by Zig, then Rust. they're very explicit while not getting in the way, you always know what throws what and what doesn't.
Rust has a little issue though, which is that people can make their functions return `Result<T, Box<dyn Error>>` which makes handling the returned error difficult, Zig does not have any of that.
As far as I know Zig errors can't carry any data along. It's nice having more details available about the failure.
Take for example if you call to an OS API and it returns an error that wasn't documented to be returned from that function. You can't return that code up the callstack using Zig's error mechanism. Instead there's functions such as unexpectedErrno and unexpectedError. Those call the appropriate method to get a string representation of the error and call std.debug.print to display it, then they just return error.Unexpected.
That means that the caller doesn't have any control over how the error is displayed. Meanwhile in Rust, you can add an UnexpectedError variant to your enum and let it carry an error code with it. The caller can then display that error however they want.
I don't hate Zig's error handling by any means, but personally I think Rust does it better. I'm happy to see that C++ seems to be going with the Rust way by adding a Result-like type std::expected.
It is true that C++ exceptions are not checked and are rarely part of the interface signature but C++ exceptions are not a tool for general error handling in the context you're comparing them against Java, Zig and Rust. Java uses exceptions for control flow while C++ doesn't. Zig and Rust don't have exceptions at all. What Zig and Rust have as error handling mechanisms C++ has them too. C++ exceptions are of a literal meaning - exceptional cases which you don't expect to happen and you usually don't know how to recover from. In this case propagating the exception up to the thread entry point and doing whatever in that case (logging, terminating, restarting, etc.) is vastly better than language forcing me to check for each possible exception all the way through the whole function callstack - it's useless.
> It is true that C++ exceptions are not checked and are rarely part of the interface signature but C++ exceptions are not a tool for general error handling
They’re literally the only way to report ctor errors.
> What Zig and Rust have as error handling mechanisms C++ has them too.
Only in the most reductive way that all langages are turing complete, in which case Java has them as well.
> They’re literally the only way to report ctor errors.
The point being? Please go find me a codebase which wraps object instantiation in try-catch clause if that's what you are trying to say. I haven't seen any.
Anyway, for that reason constructors are always written so that they cannot fail in hideous ways, and if there is no other way around it there is always 2-phase initialization (personally I think it's an anti-pattern).
> Only in the most reductive way that all langages are turing complete, in which case Java has them as well.
Nonsense. Zig AFAIU abstracts error types as some sort of integer enums while OTOH Rust has Result<T, E>. C++ has both of those mechanisms baked either into the language (enum) or standard library (std::expected, std::optional).
Go’s solution is like people couldn’t decide on if they should turn left, or turn right to avoid the cliff, so to make everyone happy they drove straight into it.
It is literally the compiler enforced shitty error handling from C’s errno that is not even a sum type.
It's one of the worst I've seen. It adds so much cognitive overhead to reading the code and makes it more annoying to write. Every function call that can fail is followed by 3 lines to check for and return the error. The actual logic quickly gets lost in there.
If it wasn't for the error handling, I would probably use Go for some of my projects. It compiles to a native, self-contained binary and still has the convenience of a garbage collector, and of course has plenty of libs available due to popularity.
ABility to ignore errors is a plus in fact. You can skip trivial non-critical problems and carry on without crashing the whole app, like it is normally done in C and C++.
It would be if you would have to explicitly opt into it via an ignored variable like _ or something. But currently with go you can accidentally ignore the error when you don't mean to.
I would argue the opposite: Junior and senior developers alike catch and swallow or log checked exceptions all over the place, making it impossible to know if your method call was successful or not.
This is why you should have code reviews. Letting juniors submit code without reviewing it is a recipe for disaster, no matter which language you are programming in.
And if it's a senior, well someone should have a word with him ..
At some point you want to swallow all checked exceptions at some point, because letting the application leak stack traces to the client is generally a bad idea.
I have a desktop application with a single exception handler wrapping it's event loop. The handler display the message to the user and returns the to loop. It's rock solid -- nothing can crash it. The user can try to save their file to some network share that just disappeared and when that fails just save again somewhere else.
But there is no such thing a safe function to call. Whether you handle errors by meticulously passing them around everywhere or not makes little difference.
(To clarify, i'm against exception based error handling, but removing checked exceptions in languages without other mechanisms of explicit error handling makes things more brittle. For example in kotlin, where some Java practices to throw all over the place are still in use, unchecked exceptions makes things worse. You wont know if a function will throw unless you inspect the code or trust it's documentation)