Having support from the language would be nice, though.
Literacy is an example. We're used to a world where it's just normal that other humans can make marks and interpret our own marks as to meaning. A thousand years ago that would be uncommon, ten thousand years ago vanishingly rare.
I really celebrate tools which take an idea that everybody agrees is a good idea, and bake it in so that everybody just has that, rather than agreeing it's a good idea but, eh, I have other things to do right now.
And it annoys me when I see these good ideas but they're left as an option, quietly for a few people to say "Oh, that's good to see" and everybody else misses out, as if "Literacy" was an optional high school class most of your peers didn't take and now they can't fucking read or write.
Example: Git has a force push feature, necessarily we can (if we have rights) overwrite a completely unrelated branch state, given any state X, now the state is our state Y instead. This isn't the default, that part is fine... Git also has "force-with-lease". This is a much better feature. Force-with-lease says "I know the current state of this branch is X, but I want to overwrite it anyway". If we're wrong, and X is not (any longer perhaps) the current state, the push fails. But force-with-lease isn't the default.
[Edited to fix clumsy wording in the last sentence]
Yes, you can counter that with GADTs and match against exhaustive subsets. But to ergonomically handle these cases, you need something like Pattern Synonyms or you drown in boilerplate.
case FILE_NOT_FOUND:
/* This is normal, nothing to do. */
break;
This should still catch adding new value into the enum and not handling it. match value {
A => { do_stuff() },
B => { unreachable!("B is not applicable here because <reason>") },
}
now when you add C you still have to match it(given the enum is exhaustive).Same as above: this solution stops working as soon as you're handling 5 out of 50 cases (or, more realistically, 10 out of 200). Lexical tokens are which always trigger the mentioned problems in my code - often you match against subsets, as there are _way_ too many of them to add them all explicitly.
Then, this "limitation" is not an argument for not running the exhaustive check. In the vast majority of cases where there are about 5 enum entries and most cases need their own path, they would be explicitly written out (i.e. no _ =>), and this works extremely well. I have had good experience, and I believe other people can attest this.
If you only have 1 case matched and everything else goes in _, later needs to add one case, you just do that, likely in every other language, there is nothing that can help. But what's described above is already a big improvement.
That's not what I wanted to express. What I wanted to say is, that even when using Haskell, which has all the possibilities to actually handle matches of subsets quite ergonomically, you can't be sure that there isn't at least one čase which isn't caught by the exhaustiveness checker (and sometimes it's just wrong, but then we're not talking about enums). So you always have to check all manually, but the checker makes that easier.
It's hard for me to think of an example where it would make even sense to "having to remember to handle the variant" rather than "handling the desired effect of the variant".