Dart compiler does not understand that the variable can not be null when I use it inside an if (x != null)
statement. It still requires to use conditional ?
or null check !
operators to access one of the variable's fields or methods.
Here is an example:
String? string;
void test() {
if (string != null) {
print(string.length);
}
}
This produces a compile-time error and says that
The property 'length' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!').
However, the receiver actually can't be null since it's wrapped with if (string != null)
block. Accessing the field with string?.length
or string!.length
works fine but it can be confusing when I need to use different fields or methods of the variable.
String? string;
void test() {
if (string != null) {
print(string.length);
print(string.isNotEmpty);
print(string.trim());
print(string.contains('x'));
}
}
All of these statements raise the same error. I also tried putting assert(string != null);
but the compiler still does not understand that the string is not null.
To give a more sophisticated example;
User? user;
@override
Widget build(BuildContext context) {
if (user == null) {
return Text('No user available');
} else {
return buildUserDetails();
}
}
Widget buildUserDetails() {
return Column(
children: [
Text(user.name),
Text(user.email),
],
);
}
This is still a problem for the compiler.
CodePudding user response:
However, the receiver actually can't be null since it's wrapped
And that assumption is plain wrong.
Your variable is a global variable and any other part of your program, through multi-threading or other shenanigans can slip in between your if
and the next line and change the variable.
That is why only local variables can be promoted to their non-null equivalent when the compiler proves that they cannot be null in certain code execution branches like an if
.
The following will work perfectly fine, because you are operating on a local variable that the compiler can be sure won't be changed by outside operations:
String? string;
void test() {
final local = string;
if (local != null) {
// here, local was promoted from "string?" to "string"
// since the "if" makes sure it is not null AND
// the variable is not accessible to anything but this
// function, so it cannot be changed from the outside
// and is contrained to the sequential flow of this method.
print(local.length);
}
}
CodePudding user response:
These are for sound null safety. Thats why whenever you start calling a functions / accessing it makes sure that the variable is not null by using ! or provide other case for null using ?.
Suppose for following case :
if (string != null) {
string=null; // Or through other function xyx() {string=null;} string becomes null then your if condition is void
print(string.length);
print(string.isNotEmpty);
print(string.trim());
print(string.contains('x'));
}
// Still sound null safety that's why above is not allowed
if (string != null) {
string=null; // Or through other function xyx() {string=null;} string becomes null then your if condition is void
print(string!.length);
print(string!.isNotEmpty);
print(string!.trim());
print(string!.contains('x'));
}
So for sound null safety it is required to be checked if string is not null before accessing it.
As per your comments you need to assign this nullable string to a non nullable string (~isdatablank~ means String was null) and proceed
String? string;
String s=string??"~isdatablank~";
if (s != "~isdatablank~") {
print(s.length);
print(s.isNotEmpty);
print(s.trim());
print(s.contains('x'));
}