How to return a non-nullable type from a Function in a function callback? - flutter

Future<int> getInt() async { // Error:
final c = Completer<int>();
await foo.bar(
callback1: (i) => c.complete(i),
callback2: (j) => c.complete(j),
error: (e) => throw e,
);
}
The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type.
As I know one of these callback will work, so how do I tell the analyzer that I've handled all the scenarios?
Note: I know I can simply use Future<int?> but I want to know if there are other ways of handling this case?

Analyzer is right here, you're just not returning anything from getInt().
Add return completer.future at the end of getInt().
Note:
Using Completer here seems rather odd, it's mainly used to bridge between callback-based API and Future-based API.

You need a return statement:
final result = await foo.bar(
callback1: (i) => c.complete(i),
callback2: (j) => c.complete(j),
error: (e) => throw e,
);
return result;
OR
...
return c;

Related

Flutter function returning at await statement

I am using flutter with the cbl package to persist data. Trying to retrieve the entries does not seem to work because the function created is returning at the await statement and not the return statement. This does not seem like the intended result of darts async/await functionality. So I am lost.
task_database.dart
Future<dynamic> getAllTasks() async {
final tasksDb = await Database.openAsync(database); <---------- Returns here
var tasksQuery = const QueryBuilder()
.select(SelectResult.all())
.from(DataSource.database(tasksDb));
final resultSet = await tasksQuery.execute();
late var task;
await for (final result in resultSet.asStream()) {
final map = result.toPlainMap();
final taskDao = TaskDao.fromJson(map);
task = taskDao.task;
// Do something with the task...
print(task);
}
;
return task; <-------------------------------------------- Does not make it here
}
task_cubit.dart
getAllTasks() => {
allTaskMap = TasksAbcDatabase().getAllTasks(),
emit(TaskState(tasks: state. Tasks))
};
What I have tried. I have tried to use Database.openSync instead of Database.openAsync however, the function just returns at the next await statement. I have also tried making getAllTasks asynchronous and awaiting the database as such.
Future<void> getAllTasks() async => {
allTaskMap = await TasksAbcDatabase().getAllTasks(),
emit(TaskState(tasks: state. Tasks))
};
However this has the same issue, when the function from task_database returns prematurely it the returns at the first await function in getAllTasks which is the allTaskMap variable.
Thanks
A function cannot "return prematurely" without a return statement.
The only way the execution is cut short would be an exception being thrown.
I also don't see how you don't get syntax errors, when you don't await the Database.openAsync(database) statement.
So make sure all your awaits are in place. Use the linter to find those that are missing. While you are at it, remove the keyword dynamic from your vocabulary, it will only hurt you if you use it without a need for it. Your return type should be properly typed, then your compiler could tell you, that returning a single task from a function that is clearly supposed to return multiple tasks is not going to work.
Either catch your exceptions and make sure you know there was one, or do not catch them and watch them go all the way through into your debugger.
In addition, following the comment of #jamesdlin, your function definitions are... valid, but probably not doing what you think they are doing.
Future<void> getAllTasks() async => {
allTaskMap = await TasksAbcDatabase().getAllTasks(),
emit(TaskState(tasks: state. Tasks))
};
needs to be
Future<void> getAllTasks() async {
allTaskMap = await TasksAbcDatabase().getAllTasks();
emit(TaskState(tasks: state. Tasks));
}

Rewrite sort((a, b) =>) to being async [duplicate]

I have this code :
widget.items.sort((a, b) {
await getItemDistance(a, true);
await getItemDistance(b, false);
return (itemADistance)
.compareTo(itemBDistance);
});
I am trying to sort widget.items list based on values returned from getItemDistance. However I get an error with a red squiggly line that says :
The await expression can only be used in an async function
and when I try to add async to the sort method I get another red squiggly line that says :
The argument type 'Future Function(Item, Item)' can't be assigned
to the parameter type 'int Function(Item, Item)'
How do I solve this dilemma guys ? :)
Thanks
List.sort is a synchronous function that expects a synchronous callback; there is no way to use it with an asynchronous callback. I would recommend transforming your List and doing any necessary asynchronous work first and then synchronously sorting the results. Doing so also should avoid calling getItemDistance (which, by virtue of being asynchronous, is likely to be expensive) on the same item multiple times. For example, something like:
final computedDistances = <Item, double>{};
for (final item in widget.items) {
final distance = await getItemDistance(item, ...);
computedDistances[item] = distance;
}
widget.items.sort((a, b) =>
computedDistances[a].compareTo(computedDistances[b])
);
(I don't know what the second argument to getItemDistance represents; if you can't get around that, you would need to build one Map with getItemDistance(..., true) results and one with getItemDistance(..., false) results1.)
As a last resort, you could write your own asynchronous sort function.
Edit #1
This should be a more efficient version since it doesn't wait for each asynchronous operation one-by-one:
final computedDistances = await Future.wait<double>([
for (final item in widget.items) getItemDistance(item, ...),
]);
final computedDistancesMap = <Item, double>{
for (var i = 0; i < widget.items.length; i += 1)
widget.items[i]: computedDistances[i],
};
widget.items.sort((a, b) =>
computedDistancesMap[a].compareTo(computedDistancesMap[b])
);
Edit #2
I've added a List.sortWithAsyncKey extension method to package:dartbag that can do this :
await widget.items.sortWithAsyncKey(
(element) => getItemDistance(element, ...),
);
1 However, if you need to call getItemDistance(..., true) for the first argument and getItemDistance(..., false) for the second argument, that implies that your comparison function probably is not self-consistent.
Whenever you are running async code you should add the async keyword like below. this tells dart you intend to run async code.
Async functions return a Future which tells dart that at some point in the future you are expecting itemADistance or an error.
You will want to return a Future of type int since you are expecting to receive an int itemADistance or an error.
Future<int> widget.items.sort((a, b) async {
await getItemDistance(a, true);
await getItemDistance(b, false);
return (itemADistance)
.compareTo(itemBDistance);
});

How to avoid nested fold in when calling multiple Future with DartZ?

I have a piece of code that look like this:
final Either<Failure, Unit> resA = await deleteA();
resA.fold(
(failure) => handleFailure(),
(success) async {
final Either<Failure, Unit> resB = await deleteB();
resB.fold(
(failure) => handleFailure(),
(success) => handleSuccess(),
);
},
);
Basically, I want to call a first function, that returns either a Failure or a Unit (the success value doesn't matter).
Then, if the first function succeeded, I want to call another function, that also return either a Future or a Unit.
How could I do to avoid this ugly nested call of fold inside another fold?
I'm working with the package dartz, which is really cool, but lacks of documentation.

how do I work with file streams in dart/flutter?

I am new to dart/flutter programming. I have been trying to analyze the content of a file and return the result but couldn't. The code actually works when in the main function, but as soon as I take it out it doesn't work anymore. I have read the dart tutorial on futures, async, await, and streams as well as watched YouTube videos but still couldn't solve the problem. I believe my problem revolves around those concepts. Here is my code:
Future<String> r(String name) async {
var f = File(name);
var lines = f.readAsLines();
await lines
.then((line) => line.forEach((element) {
if (element.contains(RegExp(r'^hello'))) {
return element;
}
}))
.onError((error, stackTrace) => 'An error occured');
}
I was getting 2 errors:
The function name 'r' was underlined:
The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type.
Try adding either a return or a throw statement at the end.
The variable 'element' was underlined:
The return type 'String' isn't a 'void', as required by the closure's context.
Thanks.
Your first error says that "Whatever happens, You have to return a String"
Your second error says that you are trying to return a String in a void function, As you see List. Foreach is a void function and you can't just return something in it because the return statement matches with the closest Function
So I rewrited you're code as following
Future<String> r(String name) async {
try {
var f = File(name);
var lines = await f.readAsLines();
for (var element in lines)
if (element.contains(RegExp(r'^hello'))) {
return element;
}
return "not found";
} catch (e) {
return 'An error occurred: $e';
}
}
Since you are using File and File.readAsLines I think it would be better to just wrap everything inside a try catch bloc k.

Getting this error, "Exception has occurred. _TypeError (type '(HttpException) => Null' is not a subtype of type '(dynamic) => dynamic')" ,

Using flutter_auth0 , getting the issue when it is directing to auth0 authenticate page for auth0.
Your immediate problem is that you have an error handler function somewhere which only accepts an HttpException as argument, but a function accepting any object is required because the type system doesn't know that you will only need to catch HttpExceptions.
I can't see from the screenshot where that function comes from, but look for a function with HttpException as argument.
(Secondarily, you are eagerly performing three HTTP requests, one POST, one GET and one PATCH request, then you only wait for one of them. You probably need to delay the client requests until you have figured out which one you want. I would either use a switch or a map of functions:
var handlers = {
"POST": () => _client.post(...),
"GET": () => _client.get(...),
"PATCH": () => _client.patch(...),
};
http.Response response = await handlers[method]();
or
http.Response response;
switch (method) {
case "POST":
response = await _client.post(...);
break;
case "GET":
response = await _client.get(...);
break;
case "PATCH":
response = await _client.patch(...);
break;
default:
throw UnsupportedError("Unknown method: $method");
}
)