Is there "!." operator in dart (flutter)? - 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.

Related

Can I simplify a condition with short-circuit call chain in Dart?

Can this code snippet be simplified on the second line?
From:
GetBuilder<ProductController>(builder: (productController) {
return productController.reviewedProductList == null || productController.reviewedProductList.length != 0
? CategoryDrinksView(productController: productController, isPopular: true)
: SizedBox();
})
To:
GetBuilder<ProductController>(builder: (productController) {
return productController.reviewedProductList?.length != 0
? CategoryDrinksView(productController: productController, isPopular: true)
: SizedBox();
})
The IDE doesn't return any errors and everything seems to work, but I would like to know if this is common in Dart and can be considered good practice.
I don't think it's a good idea. You may get a 'NoSuchMethodError: The getter 'length' was called on null' error, if the value of reviewedProductList was null. So keep the double checking

Flutter functions Null safety errors

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();

rephrase the if statement in Dart 2.0 using null

I have following statement in flutter. weight is the text from _weightController i.e. _weightController.text
int.parse(weight).toString().isNotEmpty && int.parse(weight) > 0
But in Dart 2.0 it is not working properly. For empty TextField, it is giving the error.
====== Exception caught by gesture ==============================
The following FormatException was thrown while handling a gesture:
Invalid number (at character 1)
The code block is like this.
if (int.parse(weight).toString().isNotEmpty && int.parse(weight) > 0)
return int.parse(weight) * multiplier;
else
print('Error');
As an alternative to the other answer, you can use the tryParse() method:
Like parse except that this function returns null where a similar call to parse would throw a FormatException, and the source must still not be null.
If you use this approach, you should check the return value for null:
String weight ="";
int number = int.tryParse(weight);
if (number !=null){
print(number );
}
else
print("error");
Don't forget to also check the variable for null with weight ? "" or with weight != null
Try this:
if (weight != null && weight.isNotEmpty) {
return int.tryParse(weight) * multiplier;
} else {
print("CoolTag: error");
return -1;
}

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;
}