-
Notifications
You must be signed in to change notification settings - Fork 1.7k
unawaited_futures doesn't work when method/function is not marked async
#57653
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
Comments
The rule's description states:
Await statements can only be used in function bodies that have been marked async. |
But |
In terms of my own code, I've rarely ever had to use |
My point is that it shouldn't matter if |
cc @bwilkerson |
Lints related to async behavior have been hotly discussed for a while. What everyone wants is to be told if they're making a mistake, but it's harder to statically determine whether a mistake has been made than might be expected. Generally speaking, you don't want to create a future and then not do something when it completes. But sometimes that is an appropriate thing to do. I don't think we ever reached consensus as to the right way to allow some futures to be ignored without letting bugs go unnoticed. I don't know what the right answer here is. We could try extending this rule to cover missing |
A 2nd rule would be good enough for me. I still have a hard time to understand why an ignored future in an async function is treated differently. |
I don't know that there's any good reason for it. It's possible that the decision was largely political rather than technical. |
Not quite. It's If you have a function that does not return Calling |
I still don't see a difference between not awaited Futures in functions marked or not marked with
|
In a function not marked I don't just mean this as "You can't use the 'await' keyword" - I mean this as "You cannot accomplish the semantics of 'await' without returning the Future or something chained from the Future". Let's take your original example and imagine the lint showed up where you propose: String doSomething() {
inviteController
..sendInvitations() // imagine we have a lint
..updateSearchTerm('');
} Now I want to fix this lint. How would I accomplish that? String doSomething() {
inviteController.sendInvitations().then(doSomethingElse); // Still a lint
inviteController.updateSearchTerm('');
} I suppose what I could do is: Future<String> doSomething() {
return inviteController.sendInvitations().then((_) {
inviteController.updateSearchTerm('');
});
} If this is our goal I think we'd be better off with two lints, one as it exists and another that says "Don't call methods which return a Future from methods which aren't |
I still don't see how this makes a difference. I made a call to a function
I can't see a reason why I should get a hint/warning in This is from a real issue I run into. In my opinion, this linter should hint about both or the rule causes more harm then benefit. I don't care about one or two rules. |
@zoechi Thank you for providing this example; it gives some great insight into your perspective on this. Looking at the scenario you just described, perhaps it would be more apt to create a new rule that suggests marking the current function body as |
Not sure about that. |
The Let me redo the example with the proposed problem function: void baz() {
foo(); // We imagine we want the unawaited future lint here.
doSomethingAfterFooCompleted();
} Let's say we get the lint, so we "fix" it. void baz() {
foo().then((_) {
doSomethingAfterFooCompleted();
}); // We're _still_ going to have an unawaited Future lint becauset .then() returned one.
} How do we escape? We probably don't want to allow you to not await the |
As far as I remember assigning the Future to a variable is a way to opt out var _ = iosink.close(); or an |
@natebosch I think this code piece you provided actually supports the case for the linter warning. This function above spawns an asynchronous task without returning its future. The caller of this function would falsely assume that the function returning means the task is completed. A linter warning here about the unused future is most welcome as it may remind the function's author that he/she may be misrepresenting what he/she is doing. Using the future by returning it would prevent that linter warning. If this function should really spawn something without returning its future, the |
Could we not lint when the future uses an // This would lint
foo().then((_) {
doSomethingAfterFooCompleted();
});
// These would not
foo().catchError((_) {});
foo().then((_) {
doSomethingAfterFooCompleted();
}, onError: (_) {});
foo().then((_) {
doSomethingAfterFooCompleted();
}).catchError((_) {}); It might be difficult to catch more complex cases, but I'd imagine this would handle most usages. |
I'm worried about lurking bugs where I call async functions from non-async functions. In my case, I never actually want to do this. I want to make the enclosing function async, await the call, and repeat as necessary. However I have no way to find these mistakes but line-by-line inspection. Please either change the unawaited_futures lint to demand unawaited() wrappers on async calls in non-async functions, as proposed. They are indeed "unawaited", are they not? Or provide some other means of identifying them. Perhaps avoid_async_from_sync. I would appreciate any suggestion of a stopgap measure for identifying these cases automatically. |
I too agree with @zoechi and @GreenAppers When not intentionally desired, It's very error-prone to call async functions from non-async functions. As the developer invokes an async function from a sync one, he/she will presume state is synchronous and function call/invocation is blocking. In my opinion this check should be automated and applied mandatorily as a warning and optionally as a tool/commandline. Hard to track this manually over old and new code. |
Any update regarding this? |
Hi @om-ha. This one has stalled a bit from lack of consensus. Since @bwilkerson: any fresh thoughts? |
@pq thanks for the insight, awaiting further thoughts from @davidmorgan and @bwilkerson. Current situation is a slippery-slope especially for newcomers. Calling async functions from sync ones will result in asynchronous execution, since the invocation is of an asynchronous function. This is contrary to what the developer would expect as he/she is working within a synchronous function. This would result in dangerous side effects and things executing in an undefined order, causing realtime errors. To overcome this slippery-slope, one has to remember that the function invoked is in fact async, or perform a sanity-check jumping to the definition of every function he/she invokes to make sure it's not async. A relevant warning/lint rule would keep everyone safe. |
Because of the above, I vouch for enforcing |
Here's my suggestion :) It's fine to use async methods from a sync method provided you do one of:
This lint could be called something like |
@davidmorgan you raise valid points. First point
Useful when delegating handling the future to another method. Second point
This is very useful for example when using Warning nameAs you said, ExamplesWarning would be emitted (lint rule would apply) when future result is not used/handled inside a synchronous function: // Emits `unhandled_futures` warning
void mySyncFunction() {
executeSomeAsyncMethod();
} There wouldn't be a warning when future result is handled inside a synchronous function: // Does NOT emit `unhandled_futures` warning
void mySyncFunction() {
final _ = executeSomeAsyncMethod();
final someFuture = executeSomeAsyncMethod();
List<Future> myFutures = [];
myFutures += executeSomeAsyncMethod();
} |
Hello, I got bitten by bugs caused by this linter behavior I did not expect: I know it doesn't resolve this with the official dart linter, but here is an immediate workaround I found to keep these bugs away from my code: I had forked an MIT version of the Dart Code Metrics project and I built a custom rule to cover this use case, you can find the code here: If you want to use this MIT-modified version of Dart Code Metrics, you can use this in your
and then use this in your
I've also emailed a link to the code to the Dart Code Metrics authors in case it helps them make this available to their licensed users too. Maybe this will help inspire someone to replicate this for the official dart SDK, I may attempt this at some point. |
but I don't get one.
Changing it to
makes the lint show up.
The text was updated successfully, but these errors were encountered: