Stream: project-error-handling

Topic: API stability of error types


view this post on Zulip Jane Lusby (Sep 20 2020 at 18:00):

it feels like api stability is probably something we will want to explore as a group and document all the options and their tradeoffs

view this post on Zulip Jane Lusby (Sep 20 2020 at 18:01):

my view is that between non exhaustive enums and opaque enums neither is "correct"

view this post on Zulip Jane Lusby (Sep 20 2020 at 18:02):

all the options have their tradeoffs and are valid and the correct one to use depends on your needs

view this post on Zulip Jake Goulding (Sep 20 2020 at 18:10):

I wholeheartedly agree. If nothing else, I'd like to raise awareness that error types are a part of the crates public API. I think it's far too easy to think of them as second-class things and not pay attention to that aspect of them.

view this post on Zulip Seán Kelleher (Sep 20 2020 at 18:43):

Jane Lusby said:

my view is that between non exhaustive enums and opaque enums neither is "correct"

What are these error types?

view this post on Zulip Jane Lusby (Sep 20 2020 at 18:44):

@Seán Kelleher I don't understand the question

view this post on Zulip Seán Kelleher (Sep 20 2020 at 18:46):

Sorry, I just didn't understand the terms; are these approaches for error handling?

view this post on Zulip Seán Kelleher (Sep 20 2020 at 18:48):

Also, I agree with the premise of supporting different approaches to error handling; I think exhaustive error handling should be possible ideally but should be opt-in, as it might not be necessary or even desirable for a given project.

view this post on Zulip oliver (Sep 20 2020 at 18:49):

Seán Kelleher said:

Sorry, I just didn't understand the terms; are these approaches for error handling?

It's not fully clear to me either, the developer documentation covering opaque
types is less than clear (no pun intended). I believe non-exhaustive refers to
cases where a match is allowed to omit one or more enum variants.

view this post on Zulip Jane Lusby (Sep 20 2020 at 19:05):

they're both approaches to structuring errors to allow later changes in backwards compatible ways

view this post on Zulip Jane Lusby (Sep 20 2020 at 19:07):

for non exhaustive you use the #[non_exhaustive] annotation on your type definition and variants to prevent downstream users from matching on them exhaustively or constructing them

view this post on Zulip Jane Lusby (Sep 20 2020 at 19:07):

in the opaque type case you hide the inner values and have a kind enum usually within a struct or something and then you expose some methods for reacting to specific error kinds

view this post on Zulip Jane Lusby (Sep 20 2020 at 19:07):

such as a kind function or maybe a PartialEq implementation or w.e

view this post on Zulip Jane Lusby (Sep 20 2020 at 19:08):

there's a lot of ways to do the opaque error type approach

view this post on Zulip Jane Lusby (Sep 20 2020 at 19:08):

I personally tend to prefer non exhaustive enums but I'll use opaque errors in cases where I want to hide internals

view this post on Zulip Jane Lusby (Sep 20 2020 at 19:08):

or when I want to have members that are shared between every error kind without repeating myself a ton

view this post on Zulip Jane Lusby (Sep 20 2020 at 19:09):

I bet you could also do some sort of associated consts thing like how tracing manages their LEVEL enum

view this post on Zulip Jane Lusby (Sep 20 2020 at 19:09):

never seen someone do that for errors tho

view this post on Zulip Jake Goulding (Sep 20 2020 at 19:14):

Is "opaque error" a term that other people use? I only know of it from my usage in SNAFU.

view this post on Zulip Jake Goulding (Sep 20 2020 at 19:18):

Stating the problem with code:

pub enum Error {
    CaseOne,
    CaseTwo { source: other_crate::SomeError },
}

With this semi-common definition, the library exposing Error can't:

without breaking its own semver

view this post on Zulip Jake Goulding (Sep 20 2020 at 19:20):

You can add #[non_exhaustive] to the enum and each variant to address some but not all of those cases.

view this post on Zulip Jake Goulding (Sep 20 2020 at 19:20):

specifically, adding that attribute allows you to

without breaking semver

view this post on Zulip Jake Goulding (Sep 20 2020 at 19:22):

That's because #[non_exhaustive] effectively adds a "fake" variant / field that is private and cannot be matched on.

view this post on Zulip oliver (Sep 20 2020 at 19:23):

Private to the downstream crates?

view this post on Zulip oliver (Sep 20 2020 at 19:25):

So upstream can't match on it explicitly but downstream extends it locally and this is enabled through non-exhaustive generic matchlogic in the upstream code

view this post on Zulip Jane Lusby (Sep 20 2020 at 19:28):

I feel like opaque type is a pretty common term in rust even outside of error handling but that might just be me

view this post on Zulip Jake Goulding (Sep 20 2020 at 19:38):

@oliver I feel like you are using "upstream" and "downstream" differently than I expect, as well as "private to".

The crate that exposes the Error enum effectively has private variants / fields thanks to non_exhaustive. This prevents a consumer of the crate from matching on those without including a catch-all pattern (..). That's what allows adding new variants / fields.

view this post on Zulip Jason Smith (Sep 20 2020 at 19:47):

https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html

Opaque Type is indeed a thing in Rust. Is this what you are referring to, or are you using the term in a more generic "the inner part of my struct is all private" manner?

view this post on Zulip Jane Lusby (Sep 20 2020 at 19:58):

ooh, I'm referring to the latter

view this post on Zulip Jane Lusby (Sep 20 2020 at 19:58):

not existential types

view this post on Zulip Jake Goulding (Sep 20 2020 at 19:59):

I’m (trying) to only say “opaque error”, related to but different from “opaque type”. My meaning is inner value/type is private.

view this post on Zulip Jake Goulding (Sep 20 2020 at 20:01):

Although I mentioned in another topic that impl Error is a possibility, but not I’ve ever seen.

view this post on Zulip Jane Lusby (Sep 20 2020 at 20:01):

I made a crate to work with impl errors but I never tried popularizing It because of probably obvious reasons

view this post on Zulip Jane Lusby (Sep 20 2020 at 20:01):

but check it out

view this post on Zulip Jake Goulding (Sep 20 2020 at 20:01):

Mostly because I think it would involve generics in a way that are uncommon.

view this post on Zulip Jane Lusby (Sep 20 2020 at 20:02):

https://docs.rs/adhocerr/0.1.2/adhocerr/

view this post on Zulip Jane Lusby (Sep 20 2020 at 20:02):

slightly off topic

view this post on Zulip Jane Lusby (Sep 20 2020 at 20:03):

back to opaque errors, Id be fine with standardizing on that terminology but we should definitely keep an eye on it to see if it's causing too much confusion with existential types

view this post on Zulip Jane Lusby (Sep 20 2020 at 20:04):

standardizing on that within discussions in the project group and in our writings* that is

view this post on Zulip Jake Goulding (Sep 20 2020 at 20:04):

I wasn’t even trying to popularize that specific term (and was surprised other people used it) 😲

view this post on Zulip must-compute (Sep 20 2020 at 20:06):

It might help avoid confusion to discuss this concept (in our writings) as "Public Error API" vs "private error fields"

view this post on Zulip must-compute (Sep 20 2020 at 20:07):

since the main concern is semver breakage, from what I understand above.

view this post on Zulip must-compute (Sep 20 2020 at 20:14):

actually nvm what I'm suggesting might also cause confusion

view this post on Zulip Jane Lusby (Sep 20 2020 at 20:37):

I wonder if it would be possible to add a feature to make the contents of an enum less exposed

view this post on Zulip Jane Lusby (Sep 20 2020 at 20:38):

I'm assuming there isn't but I don't know the history behind the decision to make enums pub by default

view this post on Zulip Jane Lusby (Sep 20 2020 at 20:38):

another thing that I think would be useful in the context of error handling is private trait impls

view this post on Zulip Joshua Nelson (Sep 20 2020 at 20:38):

Jane Lusby said:

I'm assuming there isn't but I don't know the history behind the decision to make enums pub by default

https://github.com/rust-lang/rust/issues/8122 has some context

view this post on Zulip oliver (Sep 20 2020 at 20:41):

Aren't there issues with fat-pointers to objects with hidden properties?

view this post on Zulip oliver (Sep 20 2020 at 20:41):

This starts to look like a FFI to me

view this post on Zulip Jane Lusby (Sep 20 2020 at 20:42):

looks like the logic was if you need a private enum you can just wrap it in a struct and it's better to have fewer keywords

view this post on Zulip Jake Goulding (Sep 20 2020 at 20:44):

Mmmmmm private trait impls.

view this post on Zulip Jane Lusby (Sep 20 2020 at 20:44):

Aren't there issues with fat-pointers to objects with hidden properties?

not sure, I didn't imagine you'd still be able to make trait objects to it, the reason I want it is so you can have from impls for external types on your error type without exposing that in your api

view this post on Zulip Jane Lusby (Sep 20 2020 at 20:44):

but I could see how that could cause issue if someone tried to turn it into a dyn From and return it from their API

view this post on Zulip oliver (Sep 20 2020 at 20:47):

I imagined that's ~how it would function.

view this post on Zulip oliver (Sep 20 2020 at 23:51):

There are also anonymous enum types

view this post on Zulip oliver (Sep 20 2020 at 23:52):

https://internals.rust-lang.org/t/ideas-around-anonymous-enum-types/12627

view this post on Zulip oliver (Sep 20 2020 at 23:53):

Maybe off topic here as well not sure

view this post on Zulip Jake Goulding (Sep 20 2020 at 23:55):

oliver said:

There are also anonymous enum types

That's effectively a large part of the discussion in #project-error-handling > Better enums

view this post on Zulip oliver (Sep 21 2020 at 15:23):

Well that's a 210 comment thread.. I'm going to need to a tl;dr summary. What
else could have parenthesis added for the group? A survey of what we are calling
opaque errors as distinct from opaque types? Do projects often accumulate
shared notes and references?

view this post on Zulip Jane Lusby (Sep 21 2020 at 16:45):

Well that's a 210 comment thread.. I'm going to need to a tl;dr summary.

There is a discussion about how best to define errors and what improvements can be made, and a lot of the early discussion in the thread centered around anon enums but that discussion didn't get super far because there are a lot of unresolved questions about stuff such as how do you unify the enums, name the types, etc

view this post on Zulip Jane Lusby (Sep 21 2020 at 16:45):

What else could have parenthesis added for the group? A survey of what we are calling
opaque errors as distinct from opaque types?

view this post on Zulip Jane Lusby (Sep 21 2020 at 16:45):

I don't understand this question

view this post on Zulip Jane Lusby (Sep 21 2020 at 16:47):

Do projects often accumulate shared notes and references?

I don't know but I think it would be a good idea for the error handling project group even if there isn't any precedent for creating shared notes and references if only because I expect a large amount of our work is going to be producing learning materials.

view this post on Zulip oliver (Sep 21 2020 at 18:14):

I'll share my notes on that forum thread when finished.


Last updated: Jan 26 2022 at 13:32 UTC