Skip to content

discarded_futures lint discussion #59887

Open
@FMorschel

Description

@FMorschel

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:

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. The unawaited_futures lint doesn't mention the unawaited 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 type Future or FutureOr 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 use await). That is, don't throw away a future, which means boils down to to not use an expression with type Future (maybe also FutureOr) in a context that isn't typed as Future or FutureOr. It being a future is lost whether the context is Object or void.

Then unawaited(someFuture) just works because someFuture is in a Future<void> context, and unawaited(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.

// CC @lrhn @pq

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3A lower priority bug or feature requestarea-devexpFor issues related to the analysis server, IDE support, linter, `dart fix`, and diagnostic messages.devexp-linterIssues with the analyzer's support for the linter packagetype-questionA question about expected behavior or functionality

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions