The description of method dart:async:Future.wait() reads:
Future
wait(
Iterablefutures, {
bool eagerError: false,
void cleanUp(
successValue
)
})
Wait for all the given futures to complete and collect their values.Returns a future which will complete once all the futures in a list are complete. If any of the futures in the list completes with an error, the resulting future also completes with an error. Otherwise the value of the returned future will be a list of all the values that were produced.
If eagerError is true, the future completes with an error immediately on the first error from one of the futures. Otherwise all futures must complete before the returned future is completed (still with the first error to occur, the remaining errors are silently dropped).
If cleanUp is provided, in the case of an error, any non-null result of a successful future is passed to cleanUp, which can then release any resources that the successful operation allocated.
The call to cleanUp should not throw. If it does, the error will be an uncaught asynchronous error.
Please, clarify the following cases:
cleanUp is provided and none of submitted futures has completed with error, will cleanUp be called at all?What I find confusing about this API is that it returns a Future, hinting that the wait function itself is async, meaning that wait does not actually wait. I know this is not true, but the API "looks" like that.
Returning a Future generally doesn't mean that the function is async. In general, we think that async should not be considered part of the signature (which is why we put it last and require the return-type to be Future).
I wrote a CL (not yet committed) that hopefully improves the documentation:
https://codereview.chromium.org/2824143002/
I think the second case is not clear enough yet.
New text reads:
In the case of an error, [cleanUp] (if provided), is invoked on any
non-null result of successful futures.
This makes it posible tocleanUpresources that would otherwise be
lost (since the returned future does not provide access to these values).
It is still silent about case "no error and cleanUp is provided". Different people may do different assumptions about this case.
Given the "in the case of an error" I would have said that it's clear that this applies to errors only, but I updated the CL.
I am confused by what you say, @floitschG.
You first said returning Future "generally doesn't mean that the function is async." Yeah, agree. Future is just a class like any others.
Then you said the async keyword "should not be considered part of the signature." How else do you know if a function is async?
And finally you confirmed that Dart "require the return-type to be Future." Does this not conflict with point 1 and 2, that the common way to tell an async function from others is NOT by its async keyword, but by its return of a Future object?
@postmasters
do you know if a function is async
What do you mean by that? Why or where would you want or need to know if it's async?
to tell an async function from others is NOT by its async keyword, but by its return of a Future object?
If async is used, the body of the method is rewritten in a way that it always returns a Future. Therefore it is just consistent to require Future as return type in the signature.
As mentioned above it's not clear to me why you would need to distinguish an async function from the outside (where the signature matters).
async only matters within the body of the method and enables you to use await.
The need arises when I care about when, and how the function is executed. If a synchronous function returns a Future, I don't really know that its work has been done. If it instead returned a, say, CompletedFuture, I would know right away that the function is synchronous. It matters because I need to know, from a glance at the API, whether special care must be taken to use that function in a non-blocking callback. Conversely, if a function is async, I need to ensure that it completes.
Perhaps I am mixing the concept of blocking vs non-blocking with sync vs async. I'll be happy to be educated further.
@postmasters
Why would it return a CompleteFuture? In this case it could just return the value (not entirely sure what you mean with CompleteFuture though).
I think you never know if the work has been done from looking at the signature.
For example:
String foo() {
new Future.delayed(const Duration(seconds: 10), () => print('done'));
return 'done (you might think)';
}
@postmasters also not sure what you mean with "blocking". There is no blocking in Dart.
@zoechi the context here is Future.wait returning a Future. And my point is that if that function is supposed to wait, it should not return a Future. But if you really want to return a Future for its subscription/listen API, return a subclass of Future would make it clearer that the Future has been completed.
There is always blocking in any language. A busy spin loop, for example, is blocking. File.createSync is blocking, etc.
The signature of a function does not include the async keyword. It should not be used to infer any performance characteristics from a function.
async to non-async. The perf characteristic is thus prone to change at any time.async functions start synchronously (until the first await).If a Future function takes time (for example, because of a very expensive loop), then this is as big of a problem as for every other function call. Since users generally expect a fast return from Future functions this should either be documented or fixed.
Edit: minor rephrasing.
Please add an pratical example of this method implementation and others. Doing this, the implementation will be much better.
Thanks