Flutter compute(): Can it be used with only one argument? - flutter

From what I'm understanding, compute() takes two arguments: the function name and a variable/argument.
However, is it possible to just run a function straight off?
I have a somewhat heavy task (parsing a JSON blob) that I want to put into a separate thread so it doesn't slow down my UI:
Future<void> fetchData({ref}) async {
....
}
It is currently being used as part of a riverpod ChangeNotifier
await ref.read(myProvider('myId')).fetchData(ref:ref);
However, now in attempting to place it in a compute:
await compute(ref.read(myProvider('myId')).fetchData,_______);
What would I place in the ______ ? I tried, null but that doesn't work. In fact nothing seems to work and the IDE is unhappy because of:
The argument type 'Future<void>' can't be assigned to the parameter type 'FutureOr<dynamic> Function(Null)'.

Related

Get the SendPort of a named ReceivePort without direct access to the ReceivePort for testing?

I am unit testing and trying to mock a class calling C functions through ffi.
A pair of functions is responsible for starting and stopping a thread in C.
The start function passes a nativePort to C to communicate with the thread.
The stop function is signaling the thread to wrap up.
The thread will then use the nativePort handle to tell the listener running in the startFunction that it finished.
DartFunc1() --ReceivePort.SendPort.nativePort--> native library in C stores port handle globally and starts processing in a thread.
DartFunc2() -> calls native C function that uses global port handle to tell dart processing ended.
In the unit test I am trying to imitate this behavior by mocking the start and stop call to C.
However, I have no idea how to get the dart sendPort to tell the listener in the other function we are done.
I spend literally all day on Google searching for similar problems (maybe hidden solutions?), looking through the documentation of mockito, flutter, the ffi package.
Somewhere I saw IsolateNameServer.lookupPortByName => SendPort? and that I can create ReceivePort with a name argument (at least for debugging), so I did that.
The code looks something like this:
test("run", () {
when(() => clib.start).thenReturn((invocation) => (_) {});
when(() => clib.stop).thenReturn(() => () {
SendPort? port = IsolateNameServer.lookupPortByName("PortA");
port?.send(1);
});
expect(sut.isRunning, false); sut.start(); // will call clib.start internally
expect(sut.isRunning, true); sut.stop(); // will call clib.stop internally
expect(sut.isRunning, false); // <= this always fails
});

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

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).

Dart: Future<void>.then(_) requires callback with parameter

I feel like I'm probably way overthinking this... but I was working with the Flutter Camera module and wrote the following code:
controller = CameraController(camera, ResolutionPreset.medium, enableAudio: false);
controller.initialize().then((_) {});
However... This confused me, as controller.initialize() returns a Future, and the .then() requires a parameter of type void. I attempted writing the .then Future without a parameter, and I got a compilation error.
So my question is: why does the callback on completion of the Future<void> need to have a parameter at all, if the result is an empty type?
Thanks for any insight!
Actually that's because of the signature of the then method.
The then method signature looks like:
Future<R> then<R>(FutureOr<R> onValue(T value), {Function onError});
As you can see the then is expecting a callback function onValue as an argument.
The onValue callback indeed takes one argument and returns a FutureOr ( FutureOr<R> is actually a type union of R and Future, meaning the return value can either be of type R or Future).
The analysis server, analysing the code will actually expect the onValue callback to match the specified type regardless of it's argument type being a void.
Hope that helps!

How to write unit test when you use Future?

I've wrote a class with some functions that does HTTP calls and returns a Future[String]. I use those functions inside a method that I need to write some tests:
def score(rawEvent: Json) = {
httpService
.get("name", formatJsonAttribute(rawEvent.name))
.onComplete { op =>
op.map { json =>
//What must be tested
}
}
}
The function onComplete doesn't have a return type - it returns Unit. How can I replace that onComplete to make my function return something to be tested?
I completely agree with #Michal, that you should always prefer map to onComplete with Futures. However I'd like to point out that, as you said yourself, what you wish to test is not the HTTP call itself (which relies on an HTTP client you probably don't need to test, a response from a server on which you may have no control, ...), but what you do with its answer.
So why not write a test, not on the function score, but on the function you wrote in your onComplete (or map, if you decided to change it)?
That way you will be able to test it with precise values for json, that you may wish to define as the result you will get from the server, but that you can control completely (for instance, you could test border cases without forcing your server to give unusual responses).
Testing that the two (HTTP call and callback function) sit well together is not a unit-test question, but an integration-test question, and should be done only once you know that your function does what is expected of it.
At that time, you will effectively need to check the value of a Future, in which case, you can use Await.result as #Michal suggested, or use the relevant constructs that your test framework gives. For instance, scalatest has an AsyncTestSuite trait for this kind of issue.
Use map instead of onComplete. It will also provide you with resolved value inside mapping function. The return type of score function will be Future[T] where T will be the result type of your processing.
In the tests you can use scala.concurrent.Await.result() function.

What's the difference between Unit and Nothing?

Both types Unit and Nothing indicate a function that does not return anything. What's the difference between them?
Unit is a type that has exactly one value ‒ see Unit type. On the other hand, Nothing has no possible value - see Bottom type.
A function that doesn't return anything must have the return type Unit. If it were Nothing then the function could not return a result. The only way to exit the function would be by an exception.
Nothing is used in a different way. It is characterized by two properties:
Nothing is a subtype of every other type (including Null).
There exist no instances of this type.
When is this useful? Consider None:
object None extends Option[Nothing]
Because Option is covariant in its type parameter and Nothing is a subtype of everything, Option[Nothing] is a subtype of Option[A] for every type A. So, we can make one object None which is a subtype of Option[A] for every A. This is reasonable, since Nothing cannot be instantiated so Option[Nothing] will always be without a value. Similarly
object Nil extends List[Nothing]
Unit corresponds to logical true and Nothing corresponds to logical false under the Curry-Howard isomorphism, where we view types as propositions and functions as proofs, .
Unit means that (a) function has side effects like input and output, (b) these side effects are the main goal of the function. Of course, a function can have side effects even if its type is different from Unit.
Nothing is a special type in Scala, because (a) it has no values (Unit has exactly one value - ()), so you cannot return a value of type Nothing, and (b) it is a subtype of every other type. That means that if something has the type Nothing, it can be used instead of any other type (via subtyping), but it won't produce any result. This is useful for dealing with exceptions - the throw expression has a type of Nothing, so it can be used everywhere in a program.
Simply, Nothing means that there was an error or termination of a program and nothing was returned, while Unit means there were side effects, but execution ended normally with no result.
Programming in Scala has a nice explanation of that.
To add one aspect to Petr's reply: Nothing plays an important role in the type hierarchy. It is a bottom type. That means that it is a subtype of every other type, which is like the opposite of Any, which is a supertype of everything. You can find a nice explanation here.
Unit
Unit is same as void of Java. void in java is a keyword but Unit is an Object in Kotlin.
Now if a function returns Unit in Kotlin, it means that it doesn't return anything meaningful, that function just executes a bunch of code and gives back the execution flow.
Nothing
Nothing is a different kind altogether. You can't relate it with anything in Java. There is nothing as such as Nothing in java.
Nothing means the end of execution. If a function returns Nothing, means literally nothing it returns. Not even the execution flow.
Nothing is like a black hole, anything that goes in doesn't come out, Not even the light (light is "execution flow" here). In the case of Unit, least light comes out.
So, if a function returns Nothing, the flow of code ends there and anything written after that is Unreachable.
Now see the code below,
fun main() {
unitFun()
println("after unit")
nothingFun()
println("after nothing") //you get warning here saying "unreachable code"
}
fun nothingFun(): Nothing {
println("inside nothing")
throw Exception()
}
fun unitFun(): Unit {
println("inside unit")
}
Output will be
inside unit
after unit
inside nothing
Exception in thread "main" java.lang.Exception
NOTE: you get warning as soon as you write
println("after nothing") UnReachable Code
And you know the reason, it's because nothingFun doesn't even send back the execution flow.
One more thing to complete this here is, any function that returns Nothing has to throw an exception of any kind.
REASON: If you write some general statement (and not throw an exception) then the function will match the return type and we don't have anything that returns Nothing, means we don't have anything that sucks the execution flow and never returns it back. Everything returns something, even Unit is something.
Now, one can say that Nothing is a class so we can make object of it and return that itself. Nohhhhhhh? A big nohhhh?
Nothing class has one constructor but it is private, so you can't even make an object of it.
Last Bit
Behind the scene, Unit is converted into void(small v) in the decompiled byte code while Nothing is converted into Void(capital V).
see the below code,
var user = null //First
var user : User? =null //Second
Here, the Second statement shows, user of Nullable-User type.
What is the type of user of the first statement?
any guess?
It's Nullable-Nothing type.
try to see the first statement as
var user : Nothing? = null
Now what's happening under the hood,
Void user = (Void)null; //First
User user = (User)null; //Second