Open filiph opened 17 hours ago
Summary: User reports a confusing Dart compile-time error when using a switch
statement with a double
. The error message incorrectly suggests a missing case, even when all seemingly relevant cases are handled.
Exhaustiveness analysis doesn't reason about the exhaustiveness of a set of double
or int
inequalities or any other number specific properties, it only reasons about properties that are modeled at the type level. So it knows that the immediate subtypes of a sealed type is an exhaustive set, it knows the complete set of values of any given enum
, it knows about null vs. non-null, etc, but it doesn't know that < 0
, > 0
and == 0
covers all values of type double
.
@bwilkerson, @pq, what do you think? Is there a good way to indicate for certain switches that exhaustiveness doesn't prove things about numbers?
it doesn't know that < 0, > 0 and == 0 covers all values of type double.
(Which it also doesn't. NaN is a thing. Even if relational operators could cover all int
s, they won't be able to cover all double
s, it would have to recognize something like double(isNaN: true)
for that, which is unlikely.)
Thanks for the clarification! In that case, I would like to see a more helpful error.
You see, modern Dart switch statements give you a lot of power, e.g. the following code gives you an exhaustiveness error which goes away when you truly cover all cases.
switch((useful, efficient)) {
case (true, true):
return "Oh boy!";
case (false, true):
return "Well, at least it's efficient.";
}
So, as a developer, it's not out of the question to half-expect a similar analysis on numbers. I, of course, accept that that isn't possible, or at least practical. But the compiler should give a better indication of what's going on than it doesn't match 'double()'
, ideally.
In other words, the quality of Dart's exhaustiveness analysis in other cases (such as records of booleans) creates an expectation with the programmer. The ensuing surprise is not helped by the error given.
I'm not sure if this is a bug but when I switch over a double and exhaustively match all possible values (I think), Dart still forces me to add an additional case.
The code above gives this compile time error:
Now it might be that I'm really missing a case but the error isn't very helpful here. Am I missing
double.nan
? (No, because "A double can't equal 'double.nan', so the condition is always 'false'.") Is itdouble.infinity
anddouble.negativeInfinity
? (No, those values are already covered, and adding them doesn't make a difference.) Is it-0
? (No. Adding-0
doesn't make a difference.) Is it null? (No, the number is non-nullable.) A specific suggestion would be much more helpful.Or maybe it's that Dart doesn't know (can't prove) what's missing for continuous values such as
double
. If that's the case, the error should note that. Something like "Switching over real numbers is not supported. You have to include adefault
case, even if you know it will never be matched."Thankfully, the workaround is easy:
;)
Dart info