-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Strange type error with generic getters #42857
Comments
This is a sharp edge of the interaction between covariant generics (unsound in general) and contra-variant type parameters. See here for more discussion, and the dart language repo issues on sound variance for more examples. TL;DR you're trying to read a field which contains an |
I don't understand where I am telling the compiler that I want it to be "the type `dynamic -> void". I don't care what the type is. I know the type is correct or it wouldn't have been able to get through the compiler. I'm not assigning the value to anything. |
In this specific case,
So in general, letting reads of this kind happen unchecked breaks the type system. You're back in unsound land. There are other things you can try to do. Some gradual type systems would wrap the callback to check its argument dynamically - we don't do that for various reasons. We've considered changing the type during the read to give you something of type As I say, an unpleasant sharp edge to the compromises we made to keep covariant generics while making the type system sound. |
Is there anything actionable here without language variance support (e.g., dart-lang/language#524 )? Could we generate a better runtime error? |
I don't really understand why we need to check the type of |
In any realistic example, it will get used. @leafpetersen mentioned other options to delay the checking, but it will have some other (probably perf) cost. E.g., in this part of @leafpetersen 's variant above, it needs to fail somewhere since the function var x = value.foo;
x("hello"); The old Dart 1 checked mode would do this check on every parameter inside the function I think the nicer answer here is to statically prevent folks from mixing |
Right. We could definitely special case the exact situation where a field is read and then immediately discarded, but I think it essentially provides zero value. More useful would be to special case a few other situations: e.g.
Not sure those provide enough value, but could be worth considering. All other options we consider make one of two tradeoffs. Either they have a large non-local perf cost, or a local perf cost + odd identity semantics, or they result in you getting a value of an "unexpected" static type. The semantics that we have chosen has reasonable perf behavior, the identity semantics that you expect (reading a field doesn't the pointer identity of the object being read), gives you a value of the static type that you expect, and in the common case just works. Unfortunately, it does have the property that in the less common case it gives the surprising behavior you see. |
The problem is that the check happens before it's assigned, so I can't even do something like: dynamic x = value.foo as dynamic; Instead I have to do: dynamic x = (value as dynamic).foo; It makes zero sense to me as a developer that the first does not work. |
Yes, this is a fair point. Enumerating a set of places where we could allow the read check to be omitted would be tedious and a bit brittle (e.g. |
@Hixie - the fundamental typing issue here is that we have a situation where the runtime type of For a developer, isn't the right outcome here getting them to change |
The code where I ran into this was where the The problem is that the failure mode is terrible. "type '(int) => Null' is not a subtype of type '(dynamic) => void'"? So what? I didn't ask for a type '(dynamic) => void'. I didn't ask for a type at all. I would be happy to assign it to a variable of type |
@vsmenon @leafpetersen Can we direct this to an open language issue? (Marking this issue as area-front-end seems a bit weird since I think we are doing what is spec'ed) |
The language issue dart-lang/language#297 is concerned with these caller-side checks, and it proposes that we give the relevant expressions a more general type (such that the static type is sound and there's no need for a check, no matter whether the value is used or discarded). |
I filed an issue around the meta problem with links to the appropriate proposals. Let's take further discussion there. |
I don't really understand why this fails:
->
The text was updated successfully, but these errors were encountered: