Flutter: can l call the same Future, first with "then()" followed by "await", without incurring in race condition issues? - flutter

I came across this piece of code on SO:
EDIT:the following code snippet is fully functional, I'm trying to understand if beside "working", can it lead to errors due to a possible race condition
if (!_downloaders.containsKey(page)) {
_downloaders[page] = NetworkProvider().getRecentPodcasts(page);
_downloaders[page].then((_) => _downloaders.remove(page));
}
final podcasts = await _downloaders[page];
and I cannot wrap my head around one part:
_downloaders[page].then((_) => _downloaders.remove(page));
here after we added a future to this Map, we execute the future by calling then(),
because we want that after the future has finished, the future is removed from the Map.
Here all is clear, but on the next line, we call await, on the Future that has been added to the Map, and which will be removed soon.
I cannot really understand how this is good code, as it looks to me that when the Future is called with the then(), I know that the code execution doesn't stop for the then() (but it does for await) , but isn't there a remote case where it might get to the await part, but the future is NOT inside the Map anymore, as it has been already removed?
Or this can never happen, and if so, can you explain me the inner workings, so I can fully graps this concept and improve my codebase

I cannot really understand how this is good code, as it looks to me that when the Future is called with the then(), I know that the code execution doesn't stop for the then() (but it does for await) , but isn't there a remote case where it might get to the await part, but the future is NOT inside the Map anymore, as it has been already removed?
Future.then() does not execute the Future's computation. Future.then() only registers a callback.
The cited code usually shouldn't be racy. Futures are normally asynchronous; even if the Future's computation is already complete, the .then() callback will not execute until the Dart runtime returns to the event loop, which in this case would happen at the await line. You can observe this:
void main() async {
print('Constructing Future');
var future = Future.sync(() => print('Ran future'));
print('Constructed Future; registering callback');
// ignore: unawaited_futures
future.then((_) => print('Ran .then() callback'));
print('Registered callback; awaiting');
await future;
print('Done');
}
which will print:
Constructing Future
Ran future
Constructed Future; registering callback
Registered callback; awaiting
Ran .then() callback
Done
It's possible (but unlikely) that the code could be racy in pathological cases. For example, Flutter provides a SynchronousFuture class that implements the Future interface but executes its .then() callback synchronously upon registration. However, that is rather unusual (and which is why the documentation for SynchronousFuture explicitly discourages using it). For that to happen, the NetworkProvider().getRecentPodcasts implementation would have to explicitly return a SynchronousFuture (or some equivalent implementation).

Related

The difference between async, async* and sync* in Flutter

I know there are async, async* and sync* in Flutter. However, I only know when and how to use async, not async* and sync*.
I know that I need to mark async for the function when the function body has await, but when to mark async* or sync*?
What is the difference between these three? Also, when and how to use them? It would be better if you could share some sample code about async, async* and sync*.
Thanks a lot if someone can tell me what the difference is. Thank you in advance!
See the Dart language tour about Generators: https://dart.dev/guides/language/language-tour#generators
In short, sync* creates an Iterable, and async* creates a Stream, and both use yield to add one element, and yield* to splice an existing iterable or stream into the result.
async
The Future class, part of dart:async, is used for getting the result of a computation after an asynchronous task has completed. This Future value is then used to do something after the computation finishes. Once the read operation is completed, the execution control is transferred within "then()".
async*
Async and Await keywords are used to provide a declarative way to define the asynchronous function and use their results. The async keyword is used when we want to declare a function as asynchronous and the await keyword is used only on asynchronous functions
sync*
In Dart language the synchronous data sequence means the instance of Iterable . The asynchronous data sequence means the instance of Stream . P.S. Generator functions can generate data items indefinitely until the function returns.

Difference between Await.result and futures.onComplete in Scala

I am using the following two code snippets to execute code in multiple threads. But I am getting different behaviour.
Snippet 1:
val futures = Future.sequence(Seq(f1, f2, f3, f4, f5))
futures.onComplete{
case Success(value) =>
case Failure(value) =>
}
Snippet 2:
Await.result(Future.sequence(Seq(f1, f2, f3, f4, f5)), Duration(500, TimeUnit.SECONDS))
In futures I am just setting some property and retrieving the result.
Note: knowing only the behaviour difference between above two snippets is sufficient.
onComplete runs on some arbitrary (unspecified) thread in the ExecutionContext, whereas Await.result runs on the current thread, and blocks it until it completes or the specified timeout is exceeded. The first is non-blocking, the second is blocking.
There's also a difference in how failures are handled in the two snippets, but this is kind of obvious from looking at the code.
Actually future.onComplete register a call back and wait for the result as soon as the future got completed control goes inside to the future, and see what the future has inside, it could be either success or failure.
On the other hand the Await blocks the thread on which the future is running until the future got completed for specific timeout.
Hence the onComplete is non blocking and Await is blocking in the nature.
If you want to use await then try collecting as much as future you can and then do Await once you should not use Await for each and every future you have In the code it will rather slow your code.

In Scala futures, should I make my functions return a Future or return a Try?

When I use Scala futures I feel confused as to whether I should return a future or return a Try. Since my code could fail, so I expect to return a Try which may have success or failure and the user of the function could use the function to create a future.
Futures can fail, yes, but that failure is self-contained--it's not going to propagate to the rest of your code. Future is very similar to Try in that sense, and in fact the value it holds is Option[Try[T]].
So when you map a Future, you'll only be handling the Success case of it's value, and if you want to handle the failures, you can use recover or recoverTo.
Future callback functions also deal with the Try directly:
Future(...).onComplete {
case Success(value) => ...
case Failure(throwable) =>
}
Stick with Future when you need async results, as it uses Try internally anyway.
If you want to get your result asynchronously you should use Future. Future has 2 types of results: Success and Failure which as you know are descendants of Try, so in any case you'll catch the failre if it happens.
Let's say I was designing yet another actor API. What should I use for result type of send? If I want clients of my code to return back to it's business as far as it possible (in other words, fire-and-forget type of sending) and process response somewhere in the future I would go with the Future. If I want to block until response will come back I will pick Try.
Hope, that makes things a bit clear for you.

Is there an F# equivalent to Scala's Promise?

Is there something like Scala's Promise in F#?
While futures are defined as a type of read-only placeholder object
created for a result which doesn’t yet exist, a promise can be thought
of as a writeable, single-assignment container, which completes a
future. That is, a promise can be used to successfully complete a
future with a value (by “completing” the promise) using the success
method. Conversely, a promise can also be used to complete a future
with an exception, by failing the promise, using the failure method.
The Async stuff covers part of this, but if you've got code that works outside the Async environment, Promises are a handy tool. (You can do things like complete a Promise in a UI thread, for example - even when the UI environment knows nothing at all about Async.)
The .Net equivalent of a promise is a TaskCompletionSource, so you can use them from F#. You can create an Async<T> from a Task<T> using Async.AwaitTask e.g.
let tcs = new TaskCompletionSource<int>()
let ta: Async<int> = Async.AwaitTask tcs.Task
//complete completion source using `SetResult`\`SetException` etc.

async ( with non-async) function control flow clarification?

( I've read a lot about async and I wonder what happens if there is a mix of async function call and non-async) and im talking about THREAD pov .
( I know that mix should not be done , but im asking in order to understand the flow better)
suppose I have(cube 1) function which calls async functions which calls asyc function.
(please notice that cube 1 function is not async)
Question : when the control reaches (cube 3) await Task.Delay(100); --
what is really happening as the control reaches cube3 await ? does the control is back(and blocked) at the pink arrow (cube 1 ) or does the control is released and still awaits ( orange arrow)
When control reaches the await statement in Cube3, Task.Delay() is called and immediately returns a Task that will complete after the delay. The rest of CalculateAnswer() is refactored into a continuation that will run when the Task returned by Delay() completes, and CalculateAnswer() immediately returns a Task<int> that will complete when that continuation completes.
CallCalculateAnswer() awaits the Task<int> returned by CalculateAnswer(), so the same logic applies: the code running after the await (i.e. the return statement) is refactored into a continuation that will run when the Task<int> completes, and CallCalculateAnswer() proceeds to return its own Task<int>.
StartChain(), however, does not await the Task<int> produced by CallCalculateAnswer(), so no continuation is generated. Instead, it stores the task into a local variable and returns. Therefore, the orange arrow in your question is the right one.
Note that, in this specific case, since nothing is done with the Task<int> returned by CallCalculateAnswer() and it is only stored in a local variable, it becomes "forgotten" once StartChain() returns: the task will complete (or fail) some time in the future, but its result (the int it produces) will be lost.
Update following comments: The pink arrow in your question implies you're expecting StartChain() to block, waiting for the task returned by CallCalculateAnswer() to complete, because it is not async and does not await that task. This is not what happens, as the usual control flow semantics apply: the method has returned a task, so you get a reference to that task and nothing more.
If you want StartChain() to block, you can use Task.Wait(), Task<T>.Result, or similar on the task returned by CallCalculateAnswer().