3 ms·
> This isn't a realistic example at all because your MyError is simple enum that you changed to make it work. Well, that's what an error is. A simple enum of t
by kaoD 8y ago
> This isn't a realistic example at all because your MyError is simple enum that you changed to make it work.
Well, that's what an error is. A simple enum of the error cases and maybe some metadata.
EDIT: e.g. IO errors in Rust's std: https://doc.rust-lang.org/src/std/io/error.rs.html#91-174 https://doc.rust-lang.org/src/std/io/error.rs.html#91-174
If your first guess is this isn't realistic because it's "too simple" then maybe you've never been exposed to this kind of error handling? It's so simple it's unbelievable?
> If you add another error
That's what I did, I added a new error.
> or have more than one level and don't eat the error now you're changing more methods, just as I said.
As I said, if you want an example with nested error types I can do it:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c4a81faf48266658f569c2a00ae10d02 https://play.rust-lang.org/?version=stable&mode=debug&editio...
As you can see, caller() (which would be our "middleman" here, the one that neither produces nor uses the error) didn't change at all.
> If you had an external compiled library the consumed MyError or called caller, you just broke it, becuase you changed the type.
You mean a dynamically-linked library? Yep, completely broken, but that's not the only problem with DLLs. Static linking is fine.
Anyways, the contract changed, so it's a breaking change, so that's good in my book. The contract changed in the case of exceptions too, you just hand-waved over the issue and called it a day.
Wouldn't it be the same with exceptions across library boundaries?
- wvenable 8y ago> If your first guess is this isn't realistic because it's "too simple" then maybe you've never been exposed to this kind of error handling? I explained why the example is too simple. If you coded this in C with an integer error code the code would also be roughly the same size. > Wouldn't it be the same with exceptions across library boundaries? Actually no. That's the significant difference. I can freely change the implementation and if that causes new and different exceptions to be possible, that doesn't affect the implementors. And most of the time such a change makes will make material affect on the implementors so they are broken for nothing.
- kaoD 8y ago> I explained why the example is too simple. And I offered a second example with a nested error, and nothing changed. Errors are just enums, there's nothing more complex than this. It's that simple. > If you coded this in C with an integer error code the code would also be roughly the same size. But it wouldn't check the error types. It's a zero-cost abstraction. > I can freely change the implementation and if that causes new and different exceptions to be possible, that doesn't affect the implementors. Neither does in my case... unless I care about the actual errors, which I did in this case in main() just for completeness.
- wvenable 8y agoHonestly, that second example is more complex. Now you're had to manually map one error onto another in order to propagate it. How big does MyError get when you have OtherError, AnotherError, FailureNum5, ChokedOnBanana. You're just doing busy work creating types and mapping them together. And this is just a simple toy example! You're quick to hand-wave that wasted effort. What value is the enum value Other(OtherError) actually provide other than to satisfy the compiler? How far do we take this when there are more levels? OtherFailure(OtherMistake(Other(OtherError)))? > Neither does in my case... In each example you changed the implementation of type so that it is no longer compatible. You altered the signature of the method. > But it wouldn't check the error types. It's a zero-cost abstraction. It's funny that you say that as error returns have a non-zero runtime cost. Yet exceptions can actually be zero-cost at runtime (if they aren't thrown) as they can be implemented out of band. Only the most naive implementation propagates exceptions with multi-value returns. Now I do understand why Rust is implemented this way but it's not because error returns are unequivocally better. Good code with exceptions have very little code actually related to error handling. Throw often, catch infrequently, and use normal resource cleanup for exceptional cleanup as well. You can get far with a 2-3 well placed catch statements and that's it. No extra typing. No error propagation code. If you think of error handling as happening where the error is raised as opposed to where it is handled it's hard to see the advantage of exceptions. Where the error is raised is not that important.
- 8y ago