Description
After some discussion over at #59877, #59331 and #58747, I've seen many users expecting discarded_futures
to work similarly to unawaited_futures
but inside synchronous code.
That is, inside synchronous code, if the Future
is assigned to something that explicitly asks for a Future
, do nothing, if not, trigger.
That would solve all of these duplicates that expect the lint not to warn when using it on FutureBuilder
from Flutter for example:
- discarded_futures lint false positive #59504
- Possible false positive in
discarded_futures
lint #58889 - update discarded_futures lint rule to not trigger when a widget expect a futur #59455
- [analyzer] False positives for discarded_futures when passing future-returning function call as an argument #59151
- discarded_futures false positive? #59387
discarded_futures
: Unwaited return for when Future is expected #59331
Making the behaviour match unawaited_futures
would also probably fix: #59204.
I've opened https://dart-review.googlesource.com/c/sdk/+/403901 and I've made some changes to address this assignability issue, but @lrhn commented on the CL:
There is no change to the description, documentation or specification of this lint, but a significant change to its behavior.
(As much as a specification exists.)Among my many beefs with this lint is that its name, description and behavior seem to be three different things. I can't tell if this change makes that better or worse.
The name is "discarded_futures". It's description (the line above and the text at https://dart.dev/tools/linter-rules/discarded_futures) is very clear that it really means "don't call async functions in non-async code".
The implementation seems to refer to the
unawaited
function in some places, which is not mentioned in the description, and isn't relevant to the specified behavior, so the implementation is either a third thing, or maybe it matches the title better than the description does. (But not well. Theunawaited_futures
lint doesn't mention theunawaited
function it the code. It doesn't have to.)I'm all for changing the specification and behavior of this lint, because "don't call async functions in non-async code" is a rule I break all the time (I know how to use
Future.then
). It's not a good lint as specified.This change seems to try to move it closer to the behavior of
unawaited_futures
, which is about not leaving a Future unawaited by accident.
That lint understands, I think, that passing a Future as an argument to a parameter of typeFuture
orFutureOr
is a way of handling that future.If this lint was to be changed, I'd probably want to change it to the exact same behavior as
unawaited_futures
, just in a non-async
function (and therefore without the ability to useawait
). That is, don't throw away a future, which means boils down to to not use an expression with typeFuture
(maybe alsoFutureOr
) in a context that isn't typed asFuture
orFutureOr
. It being a future is lost whether the context isObject
orvoid
.Then
unawaited(someFuture)
just works becausesomeFuture
is in aFuture<void>
context, andunawaited(someFuture)
has type void.All this special-casing of when it's OK to have a future feels like overkill.
It's OK to have a future in a place where a future is expected, anything else won't know to treat > it as a future.
I'm opening this issue to track this discussion and hopefully to make that change.