-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Add unawaited
to package:meta.
#33962
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
Conversation
This marks an interesting departure. Prior to this the @leafpetersen @lrhn @eernstg Given that the language does not allow annotations to be associated with expressions (or statements, or anything other than declarations), what are your thoughts on using functions to annotate expressions? If we decide to add this function, we might also consider putting it and any similar future functions in a separate library. |
Thanks. For context, see discussion on dart-lints@. The other option considered was using a comment:
But there seemed to be slight preference for a function. |
Wow, that's a long thread. I don't like the idea of a second comment-format for ignoring hints. Such "enhancements" tend to multiply to the point where they become unusable. Given that there are other functions already being proposed, I'd really like to see them in a separate library, perhaps one dedicated to support (functions or annotations) related to dart:async. |
Yes, it's a hot topic :) The other suggested methods were (I hadn't actually worked out that the name |
Oh, well, that's likely to be a whole other ball of wax. There has been strong opposition in the past to putting anything that controls the behaviors of the various compilers anywhere other than in the Of course, |
Luckily the lint is already unusable today (internally), so this makes it usable! If the trade-off is that we need to add a no-op function into a package whose goal is entirely to allow different types of static analysis, so be it?
I don't know anywhere there is a rule written that
There is already such configuration in But as you mentioned, neither |
I'll note that by "enhancements" I was referring to additional comment structures, not functions. I don't want analyzer to have to try to interpret lots of different comment structures, nor have to worry about possible conflicts with comments that were not intended to suppress errors but happen to do so.
So, again, I never claimed that there's any rule. I was merely noting that this is a change from what we have accepted into the package before. I didn't even claim that the change was bad, only that I thought it was worth thinking about before accepting it. Also, note that I said "library", not "package". We already have multiple libraries in the package, and I think it's worth considering whether we want this function to be in a separate library. (And while it's not a rule, I will point out that the README states:
so we might also want to expand the README if we're adding this.) |
I thought the point of the linter was to do extra analysis you didn't want on (by default). It seems reasonable that if we opt into
I'd be very happy to help expand the README. |
We're obviously not communicating well :-) Apologies for my part in it. I'll try again to be clear.
Yes. The point of the linter is to do extra analysis that should be optional. Yes, if a user opts into a lint rule then the lint should run. But that's not what I'm talking about. I was assuming a familiarity with the implementation that might not exist. We have architected the linter in order to attempt to make it as easy as possible to write lint rules. One aspect of that was a decision to not require lint authors to be concerned with whether their lint is being ignored in some location. The whole "ignore" comment mechanism is handled as a post-processing step. Lint authors generate all lints and the linter framework weeds out the ones that shouldn't be reported. I don't want to ask lint authors to add code to check whether there is a special comment that disables their lint. But I also don't want to try to teach the linter framework about a large number of possible comment contents that should disable specific lints. There are several negatives to either approach, and I don't think either would be a positive change to the lint ecosystem.
I missed commenting on this the first time, but I think it's important to clear up a potential misunderstanding. That library is not used by dart2js. The meta package was created by the analyzer team in order to define annotations (or functions, or whatever) that are used by the analyzer to provide additional hints or lints. The annotations in that library are specifically designed to provide additional analysis for users writing code that is expected to be compiled by dart2js. But dart2js does not use those annotations. As long as none of the backends (other than analyzer) need to have special knowledge of the functions that are being proposed, then there won't likely be any push back. But that is one of my concerns (though previously not explicitly expressed): the analyzer doesn't need to know about these functions either. The function I would like to preserve the use of the meta package for things that are used by the analyzer. I understand the convenience argument, and I'm not necessarily saying "no", but I really don't want this package to be a catch all for things not needed by the analyzer. The |
No worries. We've tried to be very transparent and have lots of discussions in the open internally in
I totally understand this requirement. I have two ideas/points:
I mean, I guess we are defining use differently. Dart2JS does check for the existence of those annotations to compile differently. But maybe the wording I am looking for is utilizing and not using?
I talked at length about this with @dgrove @leafpetersen and @vsmenon already before suggesting these changes, and I did not get any pushback. If there is anyone else you feel I should try and reach out to/convince I'm happy to spend the time.
I guess I misunderstand, the idea was to statically check that
We can track the requirements for specific functions (like (Whether Dart2JS decides to emit different code in an unsafe/non-spec mode for that function is an entirely different discussion unrelated to this request or the analyzer) |
Unfortunately, I'm not subscribed to that group. I don't have time to engage in all of the conversations there. I do care about the linter, but most of the conversations appear to revolve around whether and how to use existing lints. When the conversation changes to one about how to change the lints, linter, or meta package, then perhaps the analyzer team could be looped in.
Sure, but I'm talking about a different kind of checking. At least in my mind they are different in significant ways.
No, I was just mistaken. Your comment prompted me to look again at the library, and I'm saddened to see that it isn't what I thought it was. The annotations do appear to be applicable only to dart2js and to have nothing to do with analyzer. Sigh.
As David already pointed out:
Analyzer won't care where the function is defined or what it's name is. The lint looks for expression statements within an async method where the type of the expression is I believe that |
OK. We are hoping to keep the current processes pretty lightweight. If you have any feedback on how we could loop in your team more appropriately - neither too much nor too little I guess is the request - then @davidmorgan can definitely keep those ideas in mind! 👍 |
Thanks Brian, Matan. I'll try to loop in people from the analyzer team on lint discussions when we start talking about changes to lints, that makes perfect sense. Brian, thanks for clearing up "library" vs "package", I also got confused on that point. I currently think It is true that the analyzer does not need to know about dart-archive/linter@master...davidmorgan:document-unawaited-futures So in my mind even though it's a no-op, and could be defined anywhere and everywhere, it is part of the linter API. Brian, do you have any suggestions for making progress on the PR, please? I agree that it needs careful consideration--it looks like you pinged various people who might weigh in but they do not seem to have done so yet :)--if the next step is to get feedback from them then I'll ping them. That said, I'm completely open to take a step back and considering other options. My impression was that the discussion had reached the bikeshedding stage and it was time to send a PR, but that may have been premature. I've updated the PR: updated README.md, added 'import dart:async', and changed the Thanks! |
Thanks! I really appreciate that. I can understand why this method could look like it's strongly related to the linter, but the more I think about it the more convinced I am that we don't want functions like As for documentation for the lint, I'd probably say something like:
That makes it clear that there's nothing special about |
Thanks Brian. That's certainly an option. My main worry is that if we set the barrier to adoption too high, people will just use In the SDK it would be much more accessible/usable, but I don't want to go down that route because I think that if/when it does make it into the SDK it should be as a keyword, not a function. If we add a function to the SDK it'll be a lot more work to clean up later than if we add it to a package. I could be persuaded on this, but I don't think there is much enthusiasm for adding this sort of thing to the SDK anyway. One option we didn't yet consider is to just define If that sounds ridiculous as a means to avoid writing '// ignore: unawaited_futures', maybe it is. But there are a few good reasons we don't want people to do that:
Maybe another way to approach this would be to ask: can we create a better story for all the lints that we know have false positives? Any ideas greatly appreciated ;) |
That's a valid concern, but even putting it in meta won't guarantee that people will add a dependency on meta rather than adding a comment. But from my perspective, adding it to meta is also a significantly bad option. :-)
I agree, it seems unlikely that we could add it to the SDK.
I believe this was mentioned in the other thread, but you could write
It has the advantage that it will often not add any lines to the code and should be fairly easy to spot in a code review (maybe even easier than
Yes, it is a bit. We discussed the format for a long time and eventually settled on this as a "least bad" option. But I'm happy to re-open the discussion if you have a better alternative.
True. I suppose we could entertain the notion of an extended syntax for lints that allows users to specify whether a lint is ignorable, and then produce a hint if there is an ignore comment for an un-ignorable lint.
I think that's a great question to ask. I don't know that I have any answers to offer, but maybe others do. |
Thanks. Let me throw it back to the (internal) gallery... |
Perhaps add some or all of the analyzer team to the mailing list? |
This doesn't scale well when there are multiple calls that aren't awaited. var _ = returnsFutureString();
_ = returnsFutureInt(); Static error, can't assign Future _ = returnsFutureString();
_ = returnsFutureInt(); Noisier and adds ceremony when refactoring code - remove the call to var _1 = returnsFutureString();
var _2 = returnsFutureInt(); Pretty ugly... |
I agree it's ugly. I did realize after writing that that if we were going to use this trick (which I don't think we are) that we should use |
My preference would be to put such functions (used to silent linter warnings) directly in the linter package. That means that devs would have to add a |
These functions would need to be used in production code, which would require a normal dependency. Depending on the linter package would pull in too many other dependencies. Putting these functions in a new package (that has no dependencies on anything else) would be much better. |
I should have say: in the linter repository . So there will be 2 packages : the current My point was that code used only to silence lints should be really close to the code defining the lints. |
I'm not sure why. Most of the functions being discussed do not need to be known to the linter. Instead, they work by changing the static type information in such a way that the lint simply won't fire. Hence, there's no reason for them to be in the linter's repo. |
Indeed, some of the contents of the package (i.e. around dynamic calls) are unrelated to the linter. |
Closing this PR in favour of creating a new package. Thanks everyone! |
(Just coming back from a nice vacation ;-) I can see that this issue was just closed, but here's my response to a question that was raised here:
In the concrete examples that I've gleaned from this long thread, it seems that the need for declaring an expression to be 'unawaited' may be caused by questionable design choices elsewhere. Here's an example that was given to show what we might do when we don't want to await a future: /* unawaited */ doSomethingAsync(); In the case where A fire-and-forget action should have some semantic encapsulation property (as in "this invocation will do things asynchronously, but nobody else depends on those things being completed", e.g., because it's writing to a finite logging buffer and it might take time until the logging process makes room for more data—but nobody else in this process depends on that). Conversely, if So, ideally, there aren't any of these call sites because fire-and-forget async functions will have return type Not so ideally there will be exceptions, but if we can make them rare then there is no need to work really hard to make them concise or convenient—in which case an For the general question about using functions to annotate expressions: I suspect that it wouldn't be very good for the overall readability of the code (and I don't know whether we can rely 100% on compilers to inline those functions, so they may also cause some overhead at run time). So if we can't avoid having them, it would at least be nice if we could use some naming convention to make them stand out as "not a real function call, just an annotation", say But my primary recommendation would be to use |
Thanks Eric. The topic of whether APIs can know if callers will always want to 'await' was discussed on the internal thread. Logging came up as an example of something it should be possible to await, but that most callers will not want to await. The main argument against using And since we want something new/different, we have a choice between making the comments more powerful and adding functions. Functions are also nicer syntactically, and that leads to the current proposal :) |
Oh, then I misunderstood. I assumed that basically all occurrences of |
Well, specifically for this case, we do mean |
Now you need a new lint |
|
:D There are a bunch of lints we don't want people to ignore, either. All the ones we've enforced so far, for example: https://github.com/dart-lang/linter/blob/master/example/google.yaml |
Adding a nicer-looking way to suppress the
unawaited_futures
lint, so we can enforce it.Once this is in and published I'll send a PR updating the lint description to point to this new way of suppressing the lint
dart-archive/linter@master...davidmorgan:document-unawaited-futures