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.
It is literally the compiler enforced shitty error handling from C’s errno that is not even a sum type.
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.
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.
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).
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.
But I don't think C#, Kotlin or Scala are less safe than Java even if they do not have the concept of checked exceptions.
head []
No monad, nothing, just an exception.>Makes it impossible to call a function safely ?? catch(Exception e) anyone?
[1] https://literatejava.com/exceptions/checked-exceptions-javas...
[0] https://www.yegor256.com/2015/07/28/checked-vs-unchecked-exc...
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.
Instead of the exception type being checked or unchecked, the throw should specify checked or unchecked.
So for example the first time the exception happens it can throw a checked exception for the caller to deal with.
If the caller doesn't deal with it it can simply throw its way all the way to the top without every single function needing to declare they handle it.