I've read the reference book about it and couple of other articles, and for the life of me I cannot understand what is the reason behind the non-exhaustive attribute.
Let me explain (wow, this is ironic from a guy who just said that he doesn't get it)
I mean, we cannot use struct that has non-exhaustive attribute outside of a current create. If that is so, why not simply NOT have that attribute and simply adjust all the missing places when we add some extra field?
Could somebody please make it clear for me?
Thank you
This isn't true. You can use a non_exaustive
type, you just can't match on its fields/variants without including a wildcard pattern to account for possible new fields.
You can use the struct outside the crate, but outside the crate, you can't assume that you know all the enum
variants or struct
fields. This means that outside of the crate, you need a wildcard match on your enum
matches, need ..
in your struct
pattern matches, can't construct struct
s with struct
literal syntax, etc.
It's useful when you might
- Add more
enum
variants (which don't have their own privacy so far) - Add
struct
fields when you don't have any private fields
The alternative for struct
s is to add a dummy private field. There is no foolproof alternative for enum
s due to the lack of per-variant privacy.
The idea is "I don't promise I won't add more fields/variants in the future" if that wasn't clear already.
It was clear. What was not clear was the motivation behind it.
Thank you, that is exactly what I was looking for.
The motivation is backwards compatibility. If you publish a crate with a public struct and then someone matches or creates a struct literal based on that, you then can't publish a new minor version with any new fields without breaking that user. Adding the attribute prevents users from using any code that would break if you added more fields.
But isn't always dropping to the default case (for example when matching enums) a risk of introducing subtle logic bugs? I mean, if I add a variant to an enum matching or not mantfhing that variant could alter what the program does.
Yes, so, it only makes sense to use non_exhaustive
on an enum where dependents matching the enum can have an appropriate default case, or shouldn’t need to match the enum. For example, consider a file parser library with a FileFormat
enum — if it gains support for additional formats, that doesn’t break any callers.
Sure, but it's always a compromise. Have you ever tried to run some app and got "file not found" response when file is clearly there and it available and permissions are fine… but the “ELF interpreter” (the binary that actually loads you binary) is not there?
It's annoying. Like: really annoying and people lose lots of time figuring out what the heck is happening the first time they hit that corner case.
And it couldn't be fixed because errno
doesn't give kernel any way to distinguish these two cases! And thus high-level program (maybe a GUI program) is also unable to distinguish these cases.
Which means that such annoyance would stay with us forvever.
With non_exaustive
you error-handling may suffer in the intermediate state (when you would go from “file not found” message to “unknown problem” error message) but eventually you would reach the stage that is clearly better.
Of course, like any facility, this feature can be misused. But it's really useful when you couldn't create the full set of possibilities in advance (as is often the case in error handling and reporting).