4 ms·
There's a tangential issue in Rust where there's a concern around if a library should be exposing the error types of its dependencies. If they are exposed, semv
by eptcyka 2y ago
There's a tangential issue in Rust where there's a concern around if a library should be exposing the error types of its dependencies. If they are exposed, semver is broken anytime a dependency is updated in a semver breaking fashion. I, in general, agree that this breaks encapsulation and is not good. However, and maybe I'm doing things wrong, but often enough there are edge cases where it is important to distinguish between different errors and adjust control flow. Often, library authors will not be able to foresee all possible usecases for their error types, so one can end up doing some horrible type casting or worse hacks to get at the actual underlying data. I'm still torn as to what is the better way forward.
- paulmd 2y agojava has the "rootCause" constructor which wraps another Exception (actually Throwable) of any type passed in. so the idiomatic way would be to create your own error types, but to pass the lower-level exception in as the rootCause so you can trace the exceptions down the stack if desired. Since the type is Throwable rather than a dependency-specific exception, this isn't exposed in the interface unless you go out of your way to cast things in an obviously dangerous way. Does that not exist in Rust?
- Dylan16807 2y agoWhen you say "obviously dangerous" do you mean "obviously breaking encapsulation" or is there a bigger issue? If there's a bigger issue then I'm not sure how it's useful for solving this problem of wanting the details.
- paulmd 2y ago"obviously breaking encapsulation", like if you pull some interface from the dependency through yours, then yeah, you're broken when they break things. That's a generalized interface problem and java can't help you anymore than rust can. But I guess it's true that it may not be obvious that library interfaces may churn unexpectedly etc, you are dependent on the good behavior of others unless you specifically take steps to abstract it. (although you do absolutely have to be careful about what you are returning in a client-facing error message etc. don't return the parts of the stack trace that leak information about your application to an actual client, they should be caught by your framework and turned into generic "4xx git rekt"/"5xx we made a fucky wucky" messages that don't reveal too much about your environment.) not a java problem specifically for either of those, it just seems odd coming from that world that there's not a concept of a "recursive exception stack" like that in rust?
- tempaccount420 2y agoI don't think errors should have to follow semver. Please, break my match on non-major version bumps, if I didn't explicitly add a catch-all case.
- tialaramex 2y agoThat's what the #[non_exhaustive] attribute is for. If a struct or enum is given this attribute then everybody else is treated as though they cannot exhaustively match it, they must write the catch all case. You (as the owner of the type) can still exhaustively match it, after all you're the one who'll get broken by your own change if you screw up - but everybody else gets told they need to write the "catch all". So, no, errors aren't special and should obey semver but you deliberately can (and should) signal that your users can't exhaustively match a thing you know will change.
- fl0ki 2y agoIt's only fair to call out that #[non_exhaustive] only helps you for the very specific case of adding new enum variants or struct fields. It does nothing for the burden of keeping all existing variants and fields compatible with any way they could have been matched. However it's also only fair to note that the Rust ecosystem does not consider every [potential] breaking change a major one. https://predr.ag/blog/some-rust-breaking-changes-do-not-require-major-version/ https://predr.ag/blog/some-rust-breaking-changes-do-not-requ...
- tempaccount420 2y agoI want to be exhaustive on my error checks. I want my match to fail if a new variant is added, so that I can handle it (even if it's just to ignore it). A big reason why refactors can be so fearless in Rust is thanks to exhaustive checks. While the 'refactor' part applies mostly to your own, 1st party code, it's also useful when upgrading 3rd party dependencies. For this reason I personally don't like `#[non_exhaustive]`. I don't expect my code to keep compiling when I upgrade the minor version of my dependencies, and as long as the reason is simple, like a new enum variant was added, then I'm happy that it errored and will happily fix it. This perfectionist attitude towards semver is why so many projects get stuck forever at v0. https://0ver.org/ https://0ver.org/