4 ms·
In theory yes. But practically there are always locations where we can't match every case, so we either have to live with a warning or add a catch-all arm. And
by ReleaseCandidat 2y ago
In theory yes. But practically there are always locations where we can't match every case, so we either have to live with a warning or add a catch-all arm. And as soon as a catch-all arm exists, we are in "not checked any more" state, but with a compiler that is supposed to check for exhaustiveness. Which is way worse if the catch-all arm isn't a `panic("Unhandled match branch!")`.
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.
- gray_-_wolf 2y agoAs long as the set is limited (as enums usually are), you can always go with the middle ground between omitted case and catch all: 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.
- ReleaseCandidat 2y agoI should have added that this solution stops working as soon as you're handling 5 out of 50 cases. Lexical tokens are which always trigger the mentioned problems in my code - often you match against subsets, are there are _way_ too many of them to add them all explicitly.
- K0nserv 2y agoYou don't have to add a catch-all arm, you can still explicitly match i.e 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).
- ReleaseCandidat 2y agoYes, I see, I should have mentioned that. 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.
- lawn 2y agoThis is true, but in my experience these are edge cases and explicitly matching everything works well 90% of the time.
- ReleaseCandidat 2y agoThis is actually the problém. I'd even say that it works like 95% of the time, that's why people (of course, I don't make such silly mistakes ;) aren't used to check where it matters. In reality the policy must be to always (whether there are or aren't working exhaustiveness checks) manually check each and every occurence when adding. Don't get mé wrong, I prefer having exhaustiveness checks, but they make the manually searching a bit less tedious, not alleviate it in total.
- rty32 2y agoFirst of all, I think there is a problem with your design if you have 50 or 200 cases. Most of the code I have seen -- in any language -- have no more than 10 cases, rarely 20. Maybe that is the issue to look at first. 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.
- ReleaseCandidat 2y ago> this "limitation" is not an argument for not running the exhaustive check. 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.