Flutter functions Null safety errors - flutter

Got the following errors and don't know how to update the code to solve it.
Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
'Function' is from 'dart:core'.
Try calling using ?.call instead.
PageName nextPage = pageName_pageFunction_mapPageName.welcomePage;
PageName nextPage2 = pageName_pageFunction_mapnextPage;
The code:
enum PageName {
welcomePage,
register,
login,
editProfile,
showProfile,
resetPassword,
errorUserExists,
}
Map<PageName, Function> pageName_pageFunction_map = {
PageName.welcomePage: showWelcomePage,
PageName.register: showRegisterPage,
PageName.login: showLoginPage,
PageName.editProfile: showEditProfile,
PageName.showProfile: showUserProfile,
PageName.resetPassword: showResetPassword,
PageName.errorUserExists: showErrorUserExists,
};
void main() {
PageName nextPage = pageName_pageFunction_map[PageName.welcomePage]();
if (nextPage != null) {
while (true) {
PageName nextPage2 = pageName_pageFunction_map[nextPage]();
if (nextPage2 != null) {
nextPage = nextPage2;
}
}
}
}
Can you help me? Thank you

The error message tell that you can't execute a function because this one might be null, and if you execute a function on a null value it will break the program. You have two solution :
First you can make sure that your function isn't null with a test :
if (myFunction != null) {
myFunction()
}
Or you can tell the compiler that your function is not null with the ! operator
myFunction!()

Error: Can't use an expression of type 'Function?' as a function
because it's potentially null.
When you look up one of your functions from the map like pageName_pageFunction_map[PageName.welcomePage] you get a value of type Function?. This is because if you enter a key which does not have a corresponding value, you will get back null from the expression.
The following error message gives you a suggestion on how to solve this problem.
'Function' is from 'dart:core'. Try calling using ?.call instead.
PageName nextPage = pageName_pageFunction_mapPageName.welcomePage;
PageName nextPage2 = pageName_pageFunction_mapnextPage;
You can place ?.call directly before the argument list () to safely call the function;
pageName_pageFunction_map[PageName.welcomePage]?.call();

Related

Proper using of question mark (null safety) in flutter

Is it equal in flutter null safety?
if(widget.mapPickerController != null){
widget.mapPickerController!.mapMoving = mapMoving;
widget.mapPickerController!.mapFinishedMoving = mapFinishedMoving;
}
widget.mapPickerController?.mapMoving = mapMoving;
widget.mapPickerController?.mapFinishedMoving = mapFinishedMoving;
Both versions should end up doing the same thing. When null-safety enabled, ?. short-circuits the rest of the expression, so if the receiver is null, the rest of the expression (including the right-hand-side of the assignment) won't be evaluated. You can observe that in the following example:
class Foo {
int value = 0;
}
int bar() {
print('Called bar');
return 42;
}
void main() {
Foo? foo = null;
foo?.value = bar();
}
where running it generates no errors and shows that bar() is never called.
That said, the second version using ?. is much less clear (which is evident from the apparent confusion in the several deleted answers) and therefore probably should be avoided.
The best way would be to introduce a local variable:
final mapPickerController = widget.mapPickerController;
if (mapPickerController != null){
mapPickerController.mapMoving = mapMoving;
mapPickerController.mapFinishedMoving = mapFinishedMoving;
}
and then you don't need to use the null-assertion operator at all, and it's slightly more efficient since you check for null only once.

Is there "!." operator in dart (flutter)?

Flutter source files contains many times code similar to this:
#override
double computeMinIntrinsicWidth(double height) {
if (child != null)
return child!.getMinIntrinsicWidth(height);
return 0.0;
}
Please explain "!." I can't find it on list of dart operators.
A postfix exclamation mark (!) takes the expression on the left and casts it to its underlying non-nullable type. So it changes:
String toString() {
if (code == 200) return 'OK';
return 'ERROR $code ${(error as String).toUpperCase()}';
}
to something like this:
String toString() {
if (code == 200) return 'OK';
return 'ERROR $code ${error!.toUpperCase()}';
}
You can read more about null safety in this document.
It's the "(not)null assertion operator" which becomes part of Dart with the Null Safety feature in the next release.

what is dart (?. ) notation refer to?

as you maybe seen before in Effective Dart: Usage
(https://dart.dev/guides/language/effective-dart/usage)
you see :
optionalThing?.isEnabled ?? false;
I know val??other is an alternative of val == null ? other : val
but I don't understand what is ?.
The ?. operator is part of the null-aware operators. This is used in the following context:
if(object != null)
{
object.method1();
}
The above can be written as object?.method1();
So a code bool isEnabled = optionalThing?.isEnabled ?? false; will translate to following:
bool isEnabled;
if(optionalThing != null)
isEnabled = optionalThing.isEnabled;
else
isEnabled = false;
That question mark is for optionals. You can find this in swift, Kotlin and typescript as well.
Following your example optionalThing?.isEnabled is the same as:
optionalThing == null ? null : optionalThing.isEnabled;
This lets you call a method or property of an object without having to check whether the object is null. In case the object is null it would return null instead of crashing and that property or method would not be called.

Dart: warning "info: This function has a return type of 'int', but doesn't end with a return statement")

I got a warning on the following piece of code, and I don't know why.
List<Map<String, int>> callNoInfo = [];
int getCallNo(String phoneNo) {
callNoInfo.forEach((item) {
if (item.containsKey(phoneNo)) {
return item[phoneNo];
}
});
return 0;
}
The warning is:
This function has a return type of 'int', but doesn't end with a return statement. (missing_return at [project_name] lib\helper\call_no.dart:35)
Can anyone tell me why this happens? thanks in advance
In the forEach method, you are creating a lambda function without explicitly defining the return type, so Dart is attempting to infer it from the return statements. If we pull the function out of the forEach method, it might help to see what I mean:
...
(item) {
if (item.containsKey(phoneNo)) {
return item[phoneNo];
}
}
...
The function includes a return statement that returns item[phoneNo], which is an int value. Using this, Dart infers that the return type of this lambda function is int. However, now that it knows this, it also notices that if the code execution does not enter the if block, there is no return statement to match the else side of the if condition. If the item object does not contain the key phoneNo, what is the method going to return?
(The answer is that the method will implicitly return null which is why the message is only a warning and not a compiler error, but the warning appears because this probably wasn't intentional by you the developer and also as a nudge to help you make your code less reliant on invisible Dart runtime magicks.)
To fix this, there needs to be another return outside of the if block:
...
(item) {
if (item.containsKey(phoneNo)) {
return item[phoneNo];
}
return 0;
}
...
However, now there's a different problem. The forEach method on lists has the following signature:
forEach(void f(E element)) → void
In fact, there are two problems. First, the method passed as the parameter needs to have a return type of void, and the forEach method itself also has a return type of void. This means that you cannot return values from within the forEach method at all.
The thing about the forEach method is that it is intended to iterate over the collection and process each of the values within it. It's not meant to (and can't) search for a value and return it once it's found. Furthermore, the iteration is exhaustive, meaning once you start it, the method cannot be stopped until each and every element in the collection has been iterated over.
Which is why, as the other answers have pointed out, what you really should be doing is using a for or for in loop:
List<Map<String, int>> callNoInfo = [];
int getCallNo(String phoneNo) {
for(var item in callNoInfo) {
if (item.containsKey(phoneNo)) {
return item[phoneNo];
}
}
return 0;
}
(I'm not sure why you don't get a compiler error for assigning a lambda function with a return value of int to the forEach method which clearly is requesting a one with a void return type. But if I had to guess, I'd say the Dart runtime treats them as compatible and reconciles the difference in return type by simply discarding the return value of the lambda function.)
You don't have an else case for the if statement inside the forEach loop. Even though you might have one at the end, it still is expecting a case everywhere.
List<Map<String, int>> callNoInfo = [];
int getCallNo(String phoneNo) {
callNoInfo.forEach((item) {
if (item.containsKey(phoneNo)) {
return item[phoneNo];
}
// you don't have a case for here since it's in a callback
});
return 0;
}
However, you could do this which uses a for in loop:
List<Map<String, int>> callNoInfo = [];
int getCallNo(String phoneNo) {
for (var item in callNoInfo) {
if (item.containsKey(phoneNo)) {
return item[phoneNo];
}
}
return 0;
}

Promise working without resolving it in protractor

The below is my page object code
this.getRowBasedOnName = function (name) {
return this.tableRows.filter(function (elem, index) {
return elem.element(by.className('ng-binding')).getText().then(function (text) {
return text.toUpperCase().substring(0, 1) === name.toUpperCase().substring(0, 1);
});
});
};
the above function is called in the same page object in another function, which is
this.clickAllProductInProgramTypeBasedOnName = function (name) {
this.getRowBasedOnName(name).then(function (requiredRow) {
requiredRow.all(by.tagName('label')).get(1).click();
});
};
but the above code throws an error in the console as requiredRow.all is not a function
but when i do the following :
this.clickAllProductInProgramTypeBasedOnName = function (name) {
var row = this.getRowBasedOnName(name)
row.all(by.tagName('label')).get(1).click();
};
this works fine and clicks the required element.
But this.getRowBasedOnName() function returns a promise, which should and can be used after resolving it uisng then function. How come it is able to work by just assigning it to a variable?
When you resolve the result of getRowBasedOnName(), which is an ElementArrayFinder, you get a regular array of elements which does not have an all() method.
You don't need to resolve the result of getRowBasedOnName() at all - let it be an ElementArrayFinder which you can chain with all() as in your second sample:
var row = this.getRowBasedOnName(name);
row.all(by.tagName('label')).get(1).click();
In other words, requiredRow is not an ElementArrayFinder, but row is.