-
Notifications
You must be signed in to change notification settings - Fork 170
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
proposal: always_specify_ambiguous_types
#4853
Comments
I would also add the following to Good Examples:
// rvalue is constructor call which fully specifies the type.
final x = Foo();
// map already specifies the types.
for (final x in map)
// list already specifies the type.
for (final x in list) |
Constructors don't guarantee the type because of factory constructors, but that one seems probably ok, yeah. For the maps and lists one I can't tell what the type of |
The one case that surprises me is that |
My suggestions are from the Plaque project's restrictions on use of the C++ "auto" keyword:
I'm not surprised you find the iterator case controversial :) |
There have been past discussions of similar lints to omit "obvious" types, see #3480 and dart-lang/lints#24. I believe, there are more issues on file around this, but I couldn't find them just now. |
Chatting a bit with @bwilkerson, my sense is that from an implementation perspective, @Hixie's initial proposal isn't tricky. That said, I do think we want to spend some time up front trying to seek some some kind of consensus on what exactly we want to implement with buy in from the Dart/Flutter community. Ideally whatever we implement would be something we'd go so far as recommending in the core or recommended (or at least flutter) lint sets. |
What is the type of
I can see why it would be controversial. My concern with final double x = 0;
final double y = 0;
final count = 0; I think an interesting question is whether I do wonder about constructors in general. It's weird to me that static (de facto factory) methods would be different than factory constructors: final Foo x = Foo.createFoo(); // variable doesn't match type name, callee is a static method => need a type
final x = Foo.thingy(); // callee is a constructor => no type
final foo = Foo.createFoo(); // callee matches type name => no type Ugh, this just makes me think the whole idea is bad. :-) |
Erik's lists in the linked issues are what I'd go for (expressions with trivial types are non-connection literals, collection literals with type arguments, collection literals containing only expressions with trivial types and the same type, constructor invocations, with type arguments if generic). The one thing I might add is Some maybes are:
I wouldn't consider a variable having the same name as a type as sufficient, because that requires me to know that the type exists. And I wouldn't want this in recommended lints. Too controversial and divisive, with no real benefit. Effectively forcing people to remove information that they want to have there, whether one agrees with that or not, is just aggravating. |
This is not a lint I'd want in the core or recommended set. It's also not a lint I would want enabled for Dart team projects either. I'd like to see It might be OK to loosen |
By comparison, the most popular lint not in a recommended set is |
|
FWIW, DCM implements |
Yeah, it's hard to get good data from that. I scraped a big corpus of pub packages and open source widgets (17,941,439 lines in 90,019 files). First, looking at local variable declarations individually:
Note that I call out uninitialized variables separately since those aren't candidates for inference, so we should expect them to be typed even by users who like inference. Looking at individual variables doesn't give us good data about stylistic preference. If it turns out that people who like types also create more local variables (or vice versa), this will be skewed. (Also, sometimes huge generated files can skew data like this.) I think a decent approximation of style preference is by looking at each file in aggregate (package would be better, but is a little harder for me to do):
Here, each data point is a single file and we count the number of annotated and unnannotated local variables (ignoring uninitialized ones completely). If every variable in the file is typed, then it's a point for "All typed". Likewise, if no variable is typed, it's a point for "All inferred". Otherwise, it's some mixture of some typed and some untyped. Those could be users who prefer typing "non-obvious" variables but inferring others. Or places where a type is needed to upcast or affect downwards inference but otherwise the user likes inference. Here's a histogram of the actual percent of locals in a file that are annotated:
It looks like overall, users prefer inference, but not by a huge amount. We could get a little more data by also looking at parameter types for function expressions, but I didn't do that here. |
Many files contain only a couple of local variables (often just one), so that can make the data appear a little more "all or nothing" since the denominator is so small. Here's the results filtered to only look at files that contain at least 10 local variables:
As expected, there are more mixed results. But otherwise, it doesn't seem to skew much. Aggregating by package might be a better way to glean the style preference of each team or user. I hacked together some code to do that:
There are enough mixed results this way that it's a bit hard to read, so just splitting down the middle:
When doing this, I noticed that my itsallwidgets.com corpus includes Flutter itself and the Flutter samples. If we're trying to figure out what the external ecosystem does, then it makes sense to skip those. Removing them from the dataset gives:
|
Thanks for putting together all of this data. I find the numbers for " |
Just a little insight from my team and I. We have Between
So basically, in our case, we would like a lint that asks to omit |
The |
Sorry if I was not very clear. We are aware of that, we simply do not use Edit:We wanted to use both lints but for different cases, that's why. Maybe some other teams/individuals out there have some similar cases. That would explain why they are mostly avoiding activating them. |
flutter/engine now uses a similar style (without any lint guardrails). |
I believe we've implemented the gist of this request with two rules, each currently experimental: It is not exactly what is requested here. |
always_specify_ambiguous_types
Description
When an unobvious type is omitted: "Specify type annotations when the type is not unambiguously obvious."
When a redundant type is given: "Omit type annotations when the type is unambiguously obvious."
Details
This lint would be like
always_specify_types
, except that in the following cases it would require that the type be omitted:Types of variables when the fully qualified name of the inferred type of the variable is identical to the variable name itself, other than for the case of the first character of the name.
Types of collection literals when they are being assigned to a field or variable of the same type as the collection type that would be inferred.
Kind
Style advice.
Bad Examples
Good Examples
Discussion
This lint is intended as a potential way to reduce verbosity without losing the benefits of clarity that come from explicit types.
It's related to
always_specify_types
,avoid_types_on_closure_parameters
, andomit_local_variable_types
. It came from discussion of the Flutter style guide.The text was updated successfully, but these errors were encountered: