-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
add .unawaited extension on Future #45284
Conversation
Not sure who is the good reviewer for it ? @bwilkerson perhaps ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is definitely an interesting idea. We previously experimented with moving the definition of the function unawaited
from pedantic
to this package, but it turned out to be too big a breaking change. This nicely avoids that issue. @davidmorgan I'd be interested to hear your thoughts about this.
However, if we do decide we want to add this I'd want to put it in a new library so that users can decide whether they want this functionality or not.
It seems like a possible path to doing what we wanted to do before: dropping the code from I think if it goes in it should be in the main library, making it the one recommended way of ignoring future results in async methods. Thanks. |
I suggest we aim for more discussion / signoff on this one as it is a big change :) it will be in scope in a lot of places. |
Yes, it probably does deserve more discussion. Perhaps we could create an issue for that purpose.
That's one of the reasons I see for moving it to a separate library. Then it's only in scope if users explicitly add it to the scope. |
@lrhn is it valid Dart to have void getter? Or should we prefer extension FutureExtension<T> on Future<T>? {
void get unawaited {}
} |
It's definitely valid in that the code has valid Dart semantics and can be run without error. I think the real question is whether it's considered to be a good API design style that we want to promote. @munificent might also have thoughts in this area. |
there's a little problem with this, fwiw void main() {
dynamic future = Future.value();
unawaited(future);
future.unawaited; // throws without cast to Future
}
void unawaited(Future<void>? future) {}
extension FutureExtension<T> on Future<T>? {
void get unawaited {}
} |
The reason to use |
pkg/meta/lib/future_extensions.dart
Outdated
library meta_future_extensions; | ||
|
||
/// Extensions that apply to futures. | ||
extension FutureExtension<T> on Future<T>? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name could be more specific. You're likely never going to need to write it, but if you are, it's nicer if it is somewhat related to the content.
Maybe MetaFutureExtension
or FutureLintExtension
. Or Just FutureLintTools
, extensions don't have to be named Extension
(we do tend to name extensions as Extension
and mixins as Mixin
because it's both their declaration and their role, but it's not a rule that you must, if you can describe their role better with other words).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like FutureLintTools
! We could also rename the lib to lint_tools.dart
. @bwilkerson WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have any problem making the name more specific, but I find "Tools" to be even more general than "Extensions", so I prefer FutureLintExtensions
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And about the library name? Should I change it to lint_tools.dart
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the general style is to use the snake-case equivalent of the declaration's name when there's a single declaration in the file, so maybe future_lint_extensions.dart
? It's kind of long, and I'm not convinced that "lint" is adding anything, either in the file name or the extension name, but I don't have a strong preference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding sibling file name like dart2js.dart
it could be worth to name it linter.dart
. It will open the door to adding annotations that can be leveraged by the linter package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About the name, as there can be several extension on the same type, we could name the extension SilentUnawaitedFuturesExtension
!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have any objection to linter.dart
. It indicates that the contents are related to the linter, which is true.
... adding annotations that can be leveraged by the linter package.
I'm not sure what you have in mind, but so far we've chosen to make enforcement of annotations be enabled by default and hence hints, rather than lints.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what you have in mind
There are several issue in the linter issue tracker mentioning annotations to know if a lint should apply or not. This linter.dart
lib could be the recipient where those annotations land.
pkg/meta/lib/future_extensions.dart
Outdated
/// Annotations that developers can use to extend [Future] capabilities. | ||
library meta_future_extensions; | ||
|
||
/// Extensions that apply to futures. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's just repeating the declaration.
Maybe:
/// Operations on futures which can help with enabling or avoiding lints.
pkg/meta/CHANGELOG.md
Outdated
@@ -1,3 +1,8 @@ | |||
## 1.3.1 | |||
|
|||
* Introduce `.unawaited` extension on `Future` used to indicates to tools that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"indicates" --> "indicate"
pkg/meta/lib/future_extensions.dart
Outdated
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
/// Annotations that developers can use to extend [Future] capabilities. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is wrong in a couple of ways. First, it isn't defining annotations, it's defining extension methods. Second, the things it's declaring can't be used to extend the capabilities of Future
, they can be used to control the behavior of a lint rule.
@@ -0,0 +1,29 @@ | |||
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are users intended to import it directly. If so, it should have a short name, like meta/lints.dart
.
Is the meta
package otherwise separated between lints and "other warnings"?
Could this file just be in src/
and be exported by meta.dart
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are users intended to import it directly.
Yes.
Is the
meta
package otherwise separated between lints and "other warnings"?
No, we haven't made such a distinction. As far as I can see there is only one annotation that is related to a lint (optionalTypeArgs
) and it's of the form that @a14n mentioned elsewhere of an annotation to suppress a lint (a "users can safely violate this lint with this API" semantic).
Could this file just be in
src/
and be exported bymeta.dart
?
Yes, but there are a couple of reasons why I'm leaning toward making it a separate top-level library:
- This is the first declaration in this package that isn't intended to be used as an annotation, and that feels like a good reason to split it out.
- There are a lot of libraries that import
meta.dart
and I don't want to make breaking changes unnecessarily. Users can import it with a prefix to help prevent collisions when we add a top-level name, but prefixes don't help with extension methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm very unconcerned about extension members colliding. It happens very rarely.
I'd be much more concerned about having to add an extra import, something people will consistently forget to do, then be annoyed and go back and add it (bonus points if we can quick-fix the import, obviously).
I think it would be a better user experience if import "package:meta/meta.dart";
would import everything you need to interact with the analyzer or linter. Otherwise someone will just introduce package:metameta/meta.dart
which exports both (I know I would).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be a better user experience if
import "package:meta/meta.dart";
would import everything you need to interact with the analyzer or linter.
Possibly, but that isn't the way the package is currently organized. Importing meta.dart
doesn't get you the dart2js-specific annotations, nor the Target
annotation used only by annotation authors. In those cases we split out the pieces that are not universally useful.
I see this the same way. This extension is only useful to users that have enabled the unawaited_futures
lint and who don't want to use // ignore
comments to disable it in specific locations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we introduce the unawaited_futures
lint as default in all new Dart projects (and we will), then it does become almost universally useful to have the helper extension.
Otherwise consider having a convenience package:meta/all.dart
which imports all the (common) annotations and functions/extensions. Maybe everything, or at least everything which isn't platform dependent.
I'd use it (well, if I used meta
at all).
Please do not land this before wider review and signoff; we will have to update a significant fraction of google-internal *.dart files based on what is decided here. We need sufficient consensus to ensure that this doesn't get deprecated (for google-internal use) as soon as it lands. We definitely don't want the end result to be that there are two widely-used ways of doing this, one in |
Understood. Would you mind adding me to those discussions so that I can track the progress of the discussions and understand the reasons for the decision(s) that are made?
Agreed. |
Any update about internal discussions? |
Sorry for the lack of update; internal discussion stalled without reaching a conclusion. The sticking point is that for long statements, the extension isn't very visible: unawaited(listener.onStateChanged(state).catchError(
(e, stackTrace) =>
_logger.warning('Failed...', e, stackTrace))); vs listener.onStateChanged(state).catchError(
(e, stackTrace) =>
_logger.warning('Failed...', e, stackTrace)).unawaited; and this observation leads specifically to a desire for the |
I personally prefer reading the So, you can look at the statement expression and think "does it have an I can see other people think otherwise. Possibly because the fear Anyone can write the extension themselves if they want to. It's not magical in any way, it's just a non- |
If all this unawaited work takes place in a new To be even funnier we could replace the |
Thanks Lasse. I don't have a super strong opinion about it, since I rarely write code that needs to Re: including both--I think we'd definitely like to end up with just the one recommended way... |
If we make the Being in the SDK would mean that you can use it without needing |
@davidmorgan - are you driving the discussion about |
@natebosch I just pinged the thread. I'm not actively pushing things forward as none of the solutions looks great to me at this point. |
It was mentioned a couple of times here and it seems to solve everyone's issue but it wasn't given much consideration. If you don't want the solution to collide and you want it visible; why not make |
Closing in favour of https://dart-review.googlesource.com/c/sdk/+/200428 |
Same as @gaaclarke , I would love to have unawaited as a keyword. It would make the code much more readable, imho. |
This will allow to silent
unawaited_futures
lint.Related to googlearchive/pedantic#82