Skip to content
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 the two new "obvious"/"non-obvious"-concerned rules also target fields and top-level variables? #5101

Open
srawlins opened this issue Sep 30, 2024 · 9 comments
Labels
lint-request type-enhancement A request for a change that isn't a bug

Comments

@srawlins
Copy link
Member

Effective Dart has a rule, "DO type annotate fields and top-level variables if the type isn't obvious". We have two new lint rules:

(Effective Dart also has "DON'T redundantly type annotate initialized local variables" which the new rules conflict with; noted.)

Would it be a gain for users, and a gain for maintainability and complexity, to change the two new lint rules to also concern themselves with top-level variables and with fields?

Note that the Effective Dart rule does not distinguish between public and private:

This rule applies to both public and private declarations. Just as type annotations on APIs help users of your code, types on private members help maintainers.

(The Effective Dart rule is sort of backed by an existing lint rule, type_annotate_public_apis, but note that that lint rule only reports on public API.)

CC @munificent @eernstg

@srawlins srawlins added type-enhancement A request for a change that isn't a bug lint-request labels Sep 30, 2024
@srawlins
Copy link
Member Author

The alternatives to not expanding the two new lint rules, are:

  • write additional sister rules, "omit_obvious_property_types" and "specify_nonobvious_property_types", to back the "DO type annotate fields and top-level variables if the type isn't obvious" Effective Dart rule, or
  • punt on backing the "DO type annotate fields and top-level variables if the type isn't obvious" Effective Dart rule with a lint rule.

@srawlins
Copy link
Member Author

A benefit of separating out the concern of top-level variables and fields into different lint rules is a consistent set of rules that back Effective Dart. Internal Google might appreciate that, and continue to use the older omit_local_variable_types rule.

@eernstg
Copy link
Member

eernstg commented Oct 1, 2024

Creating a couple of new lints would make a lot of sense! The fact that local variables and static/top-level variables have different dependency relations to other parts of the given software system already gives a strong hint that they might be treated differently by developers/organizations for good reasons.

I think it should be possible to reuse hasObviousType directly. It does give an identifier that denotes a local variable a special treatment, and that case will never be reached when asking whether the declared type of a static/top-level variable is obvious. That shouldn't create any difficulties or wrong outcomes, it will only give rise to a tiny bit of wasted work (when we're testing whether an identifier denotes a local variable, and the outcome is always 'false').

(Effective Dart also has "DON'T redundantly type annotate initialized local variables" which the new rules conflict with; noted.)

I don't think it needs to be seen as a conflict.

In particular, we don't have to interpret 'redundantly' strictly as "the type annotation specifies the same type as the one that inference would have provided if the type annotation had not been there".

If the type annotation makes the code more readable for a human reader then I would not consider it to be redundant (and in that case I honestly don't care that those two types are identical, if the human reader needs to know the type, and it is not readily available).

Another case is when subtle changes in the typing of other expressions in the same function body cause the code to have inscrutable compile-time errors, or (worse) wrong behavior at run time. A well-placed type annotation on a local variable could make the code more robust against said subtle changes: Perhaps you don't get the wrong behavior in the first place, or you get a compile-time error rather than a silent propagation of subtly different types to many locations in this function body. Such a well-placed type annotation can make the code more robust when subjected to evolution of the software that it depends on (especially if it's in a different package, maintained by a different group of people). In short, the type annotation makes certain assumptions in the code explicit because we'd like to either confirm that they still hold, or we'd like to hear about it if they don't. Again: Not redundant, because it is a non-zero loss for developers who are managing code over time, if the type annotation is removed.

The whole point in having omit_obvious_local_variable_types is that it allows developers to omit type annotations on local variables whenever they want, and it nudges them to do so when the type is "obvious", but it provides a certain amount of wiggle room such that developers can include the occasional type annotation because they don't think it's redundant.

@eernstg
Copy link
Member

eernstg commented Oct 2, 2024

https://dart-review.googlesource.com/c/sdk/+/387960 implements those lints (they're not very different from the _local_variables version of the same lints). One difficulty came up, though: specify_nonobvious_property_types should not flag an instance variable with no type annotation if that type annotation is obtained by override inference.

class A {
  final num x = 1;
}

class B implements A {
  final x = 2.5; // OK, and it has type `num`.
}

How would the lint detect this?

@srawlins
Copy link
Member Author

srawlins commented Oct 2, 2024

How would the lint detect this?

Yeah, tricky. If I understand the problem, we kind of need to know whether A.x has an explicit type annotation. But A might be declared in a different library, such that we only have summary data, which I don't think would contain info about whether a field declaration has an explicit type. (Maybe we could add that.) Also, B.x could be overriding a getter/setter pair, and the components of the getter/setter pair may be declared / typed in different places in the hierarchy.

This is in particular interesting because of the proposed override keyword, yes?

@srawlins
Copy link
Member Author

srawlins commented Oct 2, 2024

@eernstg I don't know if you have a round-up of folks who's opinions is driving your omit_obvious_local_variable_types and
specify_nonobvious_local_variable_types rules, but seeing as how you've uploaded https://dart-review.googlesource.com/c/sdk/+/387960, would it make sense to prioritize those rules too, and have all 4 available as experimental lint rules that flutter repositories in particular could dogfood?

@eernstg
Copy link
Member

eernstg commented Oct 3, 2024

If I understand the problem, we kind of need to know whether A.x has an explicit type annotation.

That's actually not necessary, we just need to know that B.x does not have an explicit type annotation, so B.x got its type from some implicit mechanism, and the mechanism that provided this type annotation was override inference.

However, it might not be that difficult after all: I do not think we have to retrace the algorithm that produced the given type annotation. That's a rather involved computation, and we don't need to compute that type. It would be sufficient to know that (1) there is no explicit type annotation, and (2) the declaration does not have a compile-time error. If we have that then I believe there is no other possibility than override inference. Also, we'd just ignore the declaration if it does have a compile-time error.

@eernstg
Copy link
Member

eernstg commented Oct 3, 2024

Right, I implemented this check and added a couple of tests, and it seems to work correctly.

@eernstg
Copy link
Member

eernstg commented Oct 3, 2024

would it make sense to prioritize those rules too, and have all 4 available

Yes, indeed!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lint-request type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

2 participants