-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unwanted Object-inference induced type errors #2 #3274
Comments
You can get the same error in a simpler way: void main() {
["", 1].sort();
} The point is simply that This is also a variance issue, but deeper. In particular, In other words, in order to be statically type safe, comparable generic things should be invariant in the type variables that are relevant to the comparison. This is probably not going to be practica. It is just too convenient, for a lot of purposes where it's not causing errors, for many classes to be covariant. So let's revisit the current approach briefly: The current approach is dynamically checked, but many classes are by convention declared to be self-comparable (so an object whose run-time type is We could also have a whole hierarchy of types that are comparable to the same common supertype I think the reasonable summary would be: Dart comparisons (including indirect usages like |
It might look like I intended this issue to be about this particular example (that is, the sort method causing a crash), but I meant it to only be an example. What I wanted to point out is that, in cases like these, one can't rely on the type checker to report that type inference "failed", or in other words, it's not possible to encode the constraint that "Object should never be inferred from two unrelated types". This constraint is useful when, for example, type signatures are being migrated, as any reported violation helps with any such migration. The observation that this is not an issue in Swift, (and probably most other mainstream languages, see #3156 (comment)) seems like evidence that this is, in fact, an issue. It appears to definitely go against what most people would have learned to expect. I agree that adjusting any core libraries to prevent such issues might not be worth the churn that it could cause and I'm not suggesting this should be done. However, It looks like this is an issue that appears to be preventable in a rather simple way with an additional analysis step, as is already being done for other issues via, for example, strict-casts, strict-raw-types or strict-inference. |
As usual, you are raising a very interesting topic! In this particular case I think the core of the type safety issue is that Comparable.compare accepts two arguments of type If we get declaration site variance then we can introduce invariance even for classes like
Swift uses invariant types in the general case. A language which is doing that doesn't have any dynamic type checks associated with variance (because it doesn't exist), so they don't have the problem. (Actually, Swift collections are treated differently, but they are also copy-on-write, so that's very different; for instance, search for 'only crashes at runtime' on this page.
I can't immediately see how this could be done in such a way that it would compensate for the inherently type-unsafe |
A "don't infer I'd normally not be too worried about that, because if you get You the point a finger to a painful point in the Dart APIs, where Dart 1 APIs did not migrate safely to the Dart 2 type system (and we have some pre-null safety APIs that didn't migrate safely to the null safe type system too).
Or, really, |
(No, really, I'm not trying to highlight any issues with the
Exactly! implicit-dynamicConsider how If the implicit-dynamic analysis step is not enabled, the following code produces no warnings: var someList = []; However, if the // Missing type argument for list literal.
// Try adding an explicit type, or remove implicit-dynamic from your analysis options file.
// vv
var someList = []; implicit-objectNow, what if there was an So, without void main() {
["", 1];
} However, if an void main() {
// Missing type argument for list literal.
// Try adding an explicit type, or remove implicit-object from your analysis options file.
//vvvvvvv
["", 1].sort();
}
an Does that make sense? |
Cf. #2539 (comment). ;-) |
I completely agree with your observation, and I am strongly in favor of having a lint or some analysis step that implements what you have proposed in your comment. |
This issue presents a similar issue as the one in #3156, but one which can't be addressed with statically checked variance.
Consider the following example:
The issue here is that the return type of the function passed to
map
is inferred to beObject
. This, in my opinion, is not very helpful and can lead to accidental runtime exceptions:Such mistakes are easy to make, and other languages have made choices that prevent such errors. Consider, for example, Swift, where returning a String and a List leads to an error at compile time.
I've alluded to a separate analysis step analogous to
implicit-dynamic
, but only forObject
-related-inferences (e.g.implicit-object
) in #3156 which could help prevent such errors. I still think that that is worth considering and could be valuable to Dart users.The text was updated successfully, but these errors were encountered: