3 ms·
> Every change requires changing every caller everywhere I don't see why.
by kaoD 8y ago
> Every change requires changing every caller everywhere
I don't see why.
- wvenable 8y agoNon-trivial changes to functions typically change what errors they will trigger. Thus changing what errors their callers will trigger. And so on. Putting error conditions in the function signature means that the signature reflects the implementation details of the function. Change those implementation details and the signature changes, affecting the callers and their signatures. Unless you abstract the error and then you lose the only advantage of passing the errors around rather than using exceptions.
- kaoD 8y agoI still don't see why. https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c65c3161570329fb22907620f4f09692 https://play.rust-lang.org/?version=stable&mode=debug&editio... Let's add a new error condition: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=841a3bb4ff75c10752f9cfd1ace3bdd5 https://play.rust-lang.org/?version=stable&mode=debug&editio... Only the function raising the error, and the consumer, had to change (and the consumer only changed because it _cared_ about the error type!) If you want an example with nested errors I can do it, you'll see it's mostly the same.
- wvenable 8y agoIf you had an external compiled library the consumed MyError or called caller, you just broke it, becuase you changed the type. This isn't a realistic example at all because your MyError is simple enum that you changed to make it work. If you add another error, or have more than one level, or call it multiple locations, and don't eat the error then now you're changing many more functions, just as I said.
- 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.