-
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
Should List foos = <Foo>[] infer as List<Foo>? #31865
Comments
At the very least I'm looking forward to more formal documentation on the Dart website (i.e. not buried in markdown files in the SDK) that I can share with both external and internal users about the proper use of type inference and types in Dart 2.0. |
Using a type annotation is to tell the analyzer to use the specified type instead of the inferred one. I think it should be either |
The language team has had discussions about "partial inference" of type annotations (e.g., Without partial inference, omitted type arguments may be provided implicitly (as |
When would you prefer using Perhaps |
I think the trade-off is that (1) |
It should absolutely not be the case that this causes runtime errors when assigning If you have a concrete example I can look at it. In general:
I agree that more documentation is needed, I hope we can get some breathing room for that soon. I do have enough slides together that I could give a pretty in-depth tech talk on this next time I'm in MTV (probably early Feb), maybe we should aim for that? |
To your subsequent examples, for completeness: class X {
// Don't infer me as List<int>
List<dynamic> anything = [1, 2, 3];
} Correct, this is inferred as
class X {
// Don't infer me as List<int>... for some reason.
List<dynamic> anything = <int>[1, 2, 3];
} Your intuition is correct, the comment is wrong. There is no inference done at all in this example: you have specified the type of the literal, so it is obeyed.
class X {
// Inferred as List<dynamic>.
List ints = <int>[];
} The comment is wrong, or misleading. The static type of the variable is |
Got it. This makes much more sense to me now, I appreciate it. So tl;dr, this is an implicit downcast we only catch at runtime. |
I'm not sure which example you mean by class X {
List foos = <Foo>[];
}
void test() {
List<Foo> x = new X().foos;
} There is an implicit downcast on the assignment to |
Just wanted to bump this for possible priority in the next breaking release (Dart3?). I've been migrating large swaths of Dart 1 code to be compatible with Dart 2 semantics and answering questions from newbies on Stack Overflow (re: Flutter). There is a lot of accidental dynanicism due to this pattern: Map map = {'hello': 'world'}; User expectation is that this infers a I think we should probably make it infer by default (i.e. treat the LHS It's possible to write an effective lint for this in the mean time, I assume. |
Partial inference on type annotations could be added to the language (that would, e.g., let I usually argue that it is too error-prone to use inference in the middle of a type annotation, and we should hence require some syntactic marker (e.g., In that case it can be addressed right now, in tools: Use |
#32634 was closed as a duplicate of this, but I think it shows a more serious problem with the same underlying cause, so I'll repeat it here. In the following example, the variable is given a partial type so that it is absolutely clear that it expects a particular kind of set. The expression then uses a factory constructor from a different type. import 'dart:collection';
void main() {
LinkedHashSet x = new Set<int>(); // A value of type 'Set<int>' can't be assigned to a variable of type 'LinkedHashSet'
} It seems unambiguous that that should be a
|
@Hixie out of curiosity, what is your reason to use |
I commented on #32634, but I don't think:
... should be a static (or runtime) error, it's valid to assign a
Regardless of preference, a lot of former Java programmers will write stuff like |
It is an error because it is not a downcast and not an upcast: Of course, if we add partial inference on type annotations then But I still think it would be error-prone to allow partial type annotation inference with exactly the same syntax as instantiate-to-bound (that is: nothing), but requesting it explicitly with |
@zoechi I wanted to be clear that I was creating a In practice this was not code I would actually ship, it was just experimental code. In Flutter's codebase, we'd put all the types on both sides. But it would not surprise me to see our developers writing this kind of code, and the fact that it fails today is very sad (and a regression from Dart1). |
LinkedHashSet x = new LinkedHashSet<int>(); |
I still have troubles to make sense of that request. I'd either write
or
or if this works (only on the phone - not tested)
as I understood from above comments the runtime type should have the generuc type from the left side in the later 2 examples. |
I like to put the type on the constructor call because that's the one that "matters", in terms of it being the actual place the type is being used. The variable is just a name for a piece of memory, the constructor is actually doing the allocation, calling the code, etc. I like to use LinkedHashMap x = <int, String>{}; |
The original question in this issue has been answered and we have a solution to avoid the problem raised. See #33119 |
An internal customer ran into this pattern today:
... where it is (properly, at least according to the new spec) inferring as
List<dynamic>
, which in turn causes runtime errors when trying to assignfoos
to a trueList<Foo>
. I understand the intention behind this:Though the following is less clear than me.
In my head
anything
should just care about being aList
, but its assigned value should be ofList<int>
, notList<dynamic>
:But I really don't understand this one:
The text was updated successfully, but these errors were encountered: