-
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
[linter] no_await_no_async #59814
Comments
Interesting. I hoped to use such or similar lint to automatically find places in the analyzer itself where we have async methods. But it seems that this is not trivial. If the return type is But if the return type is a |
@scheglov Just complaining about the What is your current status on this issue? I see it's already in code review. What approach did you choose? |
My current approach is to report when a fix can be done without changing the type. In a separate discussion @srawlins pointed out that we can also support |
And my comments on the CL are to the effect that I think the lint should report in all cases, irrespective of whether we can write an automated fix for it. I can't think of any code that involves using an |
Rewriting Future<int> f() async {
return 0;
} into Future<int> f() {
return Future.value(0);
} is possible, but not desirable. |
Yeah I can see how replacing |
I'd see that happening (the preference for If I could have a nudge (discussed at #58862) telling me the return type could be changed I'd really like that. So that for functions that are used often that were once async for some depency that is not needed anymore can have a small performance gain (we could start with deprecation but that would be easy to do) or even for helper functions used sporadically that can easily be refactored. This, I guess, would be another issue, I'll open it later for a future discussion if anyone likes the idea. |
Benchmark codeFuture<int> getValueAsync() async {
return 42;
}
Future<int> getValueFuture() {
return Future.value(42);
}
int getValueSync() {
return 42;
}
Future<void> runAsyncBenchmark() async {
final timer = Stopwatch()..start();
var acc = 0;
for (var i = 0; i < 10000000; i++) {
acc = (acc + await getValueAsync()) & 0xFFFFFF;
}
timer.stop();
print(' Async Benchmark: ${timer.elapsedMicroseconds} us');
}
Future<void> runFutureBenchmark() async {
final timer = Stopwatch()..start();
var acc = 0;
for (var i = 0; i < 10000000; i++) {
acc = (acc + await getValueFuture()) & 0xFFFFFF;
}
timer.stop();
print('Future Benchmark: ${timer.elapsedMicroseconds} us');
}
void main() async {
// Warm-up (very basic in this example)
print('--- warm-up');
await runAsyncBenchmark();
await runFutureBenchmark();
// Run benchmarks for measurement
print('--- benchmark');
await runAsyncBenchmark();
await runFutureBenchmark();
} Results
It looks that |
When we can change the return type, it would be really good to do so. Benchmark codeFuture<int> getValueAsync() async {
return 42;
}
int getValueSync() {
return 42;
}
Future<void> runAsyncBenchmark() async {
final timer = Stopwatch()..start();
var acc = 0;
for (var i = 0; i < 10000000; i++) {
acc = (acc + await getValueAsync()) & 0xFFFFFF;
}
timer.stop();
print('Async Benchmark: ${timer.elapsedMicroseconds} us');
}
Future<void> runSyncBenchmark() async {
final timer = Stopwatch()..start();
var acc = 0;
for (var i = 0; i < 10000000; i++) {
acc = (acc + getValueSync()) & 0xFFFFFF;
}
timer.stop();
print(' Sync Benchmark: ${timer.elapsedMicroseconds} us');
}
void main() async {
// Warm-up (very basic in this example)
print('--- warm-up');
await runAsyncBenchmark();
await runSyncBenchmark();
// Run benchmarks for measurement
print('--- benchmark');
await runAsyncBenchmark();
await runSyncBenchmark();
} Results
It looks more than 100x faster for this trivial code. |
I'd also like to mention dart-lang/language#870 related to the return of |
Hi @scheglov, if you don't mind, here are a few missing test cases that can help avoid some false positives: // 1, same applies to IfElement
Future<void> function() async {
final stream = Stream.fromIterable(['1', '2', '3', '4']);
await for (var s in stream) {
print(s);
}
}
// 2, AFAIK async won't be highlighted right now, but should be
Future<String> anotherAsyncMethod() async => Future.value('value');
// 3, the body has implicit return (useFunction is copied from your test cases)
useFunction(() async {
if (condition) return Future.value('value');
});
// 4, removing async will make the return type Future<String?>?
Future<String?> get(String? x) async => x == null ? null : Future.value(x); |
Thank you, @incendial. Yes, I found (3) while working https://dart-review.googlesource.com/c/sdk/+/403082 And I forgot (1) about And we need support for And we need to check for nullable |
I think we have two properties of a function here: internal and external.
|
Yep, that's what I meant |
I think this may be the same as #58901? |
I think it's important to separate the question of which cases the lint should flag and the question of which fixes we should automate. Are you suggesting that Future<int> f() async {
return 0;
} shouldn't be flagged by the lint, or that the one possible fix that I mentioned shouldn't be implemented? |
I think for code Future<int> f() async {
return 0;
} we don't want to report the lint because we don't know how But an Quick Assist to convert into int f() {
return 0;
} would be fine, because we expect that the user knows what he is doing, and will update any follow-up errors, or revert the change. |
https://dart-review.googlesource.com/c/sdk/+/403320 should fix false positives and false negatives mentioned above. |
Bug: #59814 Change-Id: Iebf90315e7c443e00ea84c380f85ac6c84bc86c6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/403320 Reviewed-by: Samuel Rawlins <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Phil Quitslund <[email protected]>
The CL landed. |
if the last await is deleted from a function, the function should not be async
The text was updated successfully, but these errors were encountered: