I'm using this repository to familiarize myself with Amazon's Cognito user system. In the file lib/screens/signup_screen.dart, starting at line 27 there is this piece of code:
TextFormField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(labelText: "Email"),
controller: _emailController,
validator: (value) =>
!validateEmail(value) ? "Email is Invalid" : null,
),
However, since we have null safety in Dart since version 2.12, this piece of code fails with the error message: The argument type 'String?' can't be assigned to the parameter type 'String'
.
What I got from that is that value may not be equal to null and the code cannot guarantee that as it is. Please correct me if I'm wrong and I'm also hoping someone can explain to me why the code cannot guarantee null safety here. If the textfield is empty, value should be equal to ""
instead of null
.
Anyhow, I decided to use the ternary operator to fix this issue:
!validateEmail(value == null ? "" : value) ? ...
Which the IDE suggested I correct to:
!validateEmail(value ?? "") ? ...
Dart also suggested to insert a null check as another alternative:
!validateEmail(value!) ? ....
Up till now, I have just been using these fixes as a workaround to produce code fast without trying to understand what's actually going on.
So what's the difference between these methods? Does the ??
in the second method have an integrated == null
check and is it exactly the same as writing value == null ? "" : value
?
Also, what does the nullcheck value!
do? Yes, it checks if value is equal to null, but what does it do for me when value is in fact equal to null?
CodePudding user response:
The ??
is a null-aware operator , which returns the expression on its left unless that expression’s value is null, in which case it evaluates and returns the expression on its right:
print(1 ?? 3); // <-- Prints 1.
print(null ?? 12); // <-- Prints 12.
Which is the same as doing a ternary operator but more readable.
The bang operator !
casts aways the nullability of the variable, meaning YOU explicitly say that the value CAN'T be null
.
Of course, like any cast, using ! comes with a loss of static safety. The cast must be checked at runtime to preserve soundness and it may fail and throw an exception.
For further reading check out the documentation.
CodePudding user response:
You can start learning more about sound null safety in Dart here: Understanding Null Safety
The null assertion value!
is equal to casting to a non-nullable type: value as String
. It raises an exception if value
is null.
The conditional ??
operator acts as you expect: value ?? ""
is a shorthand equivalent for value != null ? value : ""
CodePudding user response:
What I got from that is that value may not be equal to null and the code cannot guarantee that as it is.
You have that backwards. value
might be null
, and the code cannot guarantee that it isn't.
can explain to me why the code cannot guarantee null safety here. If the textfield is empty, value should be equal to
""
instead ofnull
.
Because that's what TextFormField
's constructor specifies. Its validator
parameter is declared to be a FormFieldValidator<String>?
, and FormFieldValidator<T>
is defined to be a String? Function(T? value)
. In other words, the validator
callback is declared to be a function that must accept null
as an argument. The compiler does not have semantic knowledge to know whether TextFormField
will actually invoke that callback with null
instead of an empty string in practice.
So what's the difference between these methods? Does the
??
in the second method have an integrated== null
check and is it exactly the same as writingvalue == null ? "" : value
?
??
is one of Dart's null-aware operators; it automatically checks for null
for you. As stated in the Dart Language Tour:
expr1 ?? expr2
If expr1 is non-null, returns its value; otherwise, evaluates and returns the value of expr2.
So yes, it is equivalent to expr1 == null ? expr2 : expr1
(except that ??
would evaluate expr1
only once, which matters if evaluation has side effects). You should prefer ??
anyway because it better conveys intent.
Also, what does the nullcheck
value!
do? Yes, it checks if value is equal to null, but what does it do for me when value is in fact equal to null?
value!
will throw an exception (specifically a TypeError
) if value
turns out to be null
at runtime. Do not use !
unless you can logically guarantee that value
will not be null
.