-
Notifications
You must be signed in to change notification settings - Fork 50
Fix places awaiting void, for dart 2. #65
Fix places awaiting void, for dart 2. #65
Conversation
Looks like cache.invalidate does do some asynchronous stuff (`splitter.close()`, but notably not `_stale.close()` which returns void). Return the future for that stuff without changing its order of operations. Also some place awaiting `expect()` which appeared to be intended to be awaiting `cancel()`, switching those still passes tests.
I'm not really actively maintaining this package anymore. |
no problem @nex3, you've reviewed a ton already today anyway! Not sure if @matanlurey is a good reviewer? Threw @kevmoo on it to have a big reviewing party. |
lib/src/async_cache.dart
Outdated
_cachedValueFuture = null; | ||
_cachedStreamSplitter?.close(); | ||
Future invalidate = _cachedStreamSplitter?.close(); |
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'd just make the function async and await here – in theory you could be avoiding some unneeded async silly if the splitter != null – but you are also adding some complexity to how this method reads.
Maybe add an await and put the null check in a block – best of both worlds?
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.
Also this is a ~breaking change – folks will start getting warnings about awaiting here if they have the lint enabled.
Why is this change needed?
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.
Well, technically I would say this is a bugfix.
If the invalidate method does asynchronous work, and the future of that work is thrown away, its impossible to await invalidation. There is at least some code (in the tests) awaiting validation, and that silently did not actually await the invalidation.
However, this could be maintained as returning void, and we could add a invalidateAsync
method which returns the future of _cachedStreamSplitter?.close()
?
Regarding the order of operations, I just really wanted to land a change that's as small as possible -- so this won't add asychrony in the void case (like before) and it won't change the order of operations vs before. Not necessarily important, and not as clean as await
ing here, but I just didn't want spooky asynchrony changes to stall the CL.
If you aren't spooked by the await I'll do that though! And do you want it to be a new method? The good news is that dart 2 will not let them use the wrong method ("you can't await invalidate() as it returns void")
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.
ping @kevmoo
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.
@matanlurey – thoughts?
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 understand how this relates to an await void
? Was something in the tests awaiting the result of this function before? Wasn't that effectively await null
? Can it still be?
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.
Yeah, a test was awaiting this method. It could definitely return null, but I would consider the following a bug:
Future f() {
spawn_async_operation_without_await();
return null;
}
"function returning future doesn't actually block until work is complete" is the title I'd give that bug!
Alternatively, and I mean this as a strawman but I also honestly prefer it, I could do
Null f() {
spawn_async_operation_without_await();
return null;
}
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.
What I mean is, the old behavior was already translatable to await null;
This isn't a case of a Future
slipping through a void
signature and being an otherwise valid await
. This is a case of a Null
going through a void
signature. I agree on principle with the idea of making this async work possible to await. But as it is this change is not maintaining the same semantics in the test.
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.
Yeah, I was careful to preserve the ordering semantics just out of conservatism, but didn't do so for this part, which is arguably inconsistent. I can leave a TODO and return null.
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.
OK done. PTAL
I went with returning Null
. I didn't have the heart to commit:
Future<void> fn() {
// TODO: await this
async_op();
// TODO: return a future
return null;
}
lib/src/async_cache.dart
Outdated
@@ -89,12 +89,13 @@ class AsyncCache<T> { | |||
} | |||
|
|||
/// Removes any cached value. | |||
void invalidate() { | |||
Future invalidate() { |
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.
how about Future<void>
?
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.
Thanks, definitely should do that..!
lib/src/async_cache.dart
Outdated
_cachedValueFuture = null; | ||
_cachedStreamSplitter?.close(); | ||
Future invalidate = _cachedStreamSplitter?.close(); |
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 understand how this relates to an await void
? Was something in the tests awaiting the result of this function before? Wasn't that effectively await null
? Can it still be?
lib/src/async_cache.dart
Outdated
_cachedStreamSplitter?.close(); | ||
_cachedStreamSplitter = null; | ||
_stale?.cancel(); | ||
_stale = null; | ||
|
||
// TODO: This does not return a future, but probably should. |
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 we can leave this method as it was (although we can either file an issue or add a TODO).
This can continue to be a void
return and we can rewrite await foo.invalidate();
to
foo.invalidate();
await null;
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.
Ah, missed your commend that you had explicitly avoided this. FWIW I prefer it since it localizes the "fix" to where the await is. It's also slightly less "breaking" to later change from void
to Future<void>
than it would be to change from Null
to Future<void>
.
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.
Part of the problem is that if this code should be awaited, because it does do asynchronous work, then I don't want to migrate all code awaiting this to no longer do so, only to then fix it and have to migrate all other code back.
This "other code" would be third party code, not internal code, though.
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.
We've decided to keep allowing await void
for now right? Maybe we should punt on this and file an issue to do the proper fix of making it return a Future
?
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.
We might still get this in in time. But its not a priority
…wait-void Fix places awaiting void, for dart 2.
Looks like cache.invalidate does do some asynchronous stuff
(
splitter.close()
, but notably not_stale.close()
which returns void).Return the future for that stuff without changing its order of
operations.
Also some place awaiting
expect()
which appeared to be intended to beawaiting
cancel()
, switching those still passes tests.