Dart/Flutter problems with null-safety

2,165

In a nutshell: if Dart is certain that a variable at compile time can be null at runtime, it doesn't compile.. unless you explicitly check for null values, and/or promote the variable to be non-nullable with the ! operator (Dart is not always able to infer the non-nullability in certain situations, so it's our responsibility to promote them to non-nullable).

There's much more to know if you're curious ("why?", for starters), so I'd suggest to check the null safety documentation (quick read).

This being said, your code now changes:

(1) We must check if val is nullable, before accessing it. We can either use ! or .? to safely access it; note: the null check operator ! is the least safe null operator, it's likely that it will result in run time exceptions.

validator: (val) {
  val==null || val?.isEmpty || val?.length<3
  ? "Enter Username 3+ characters"
  : null
}

(2) I can't infer which method / variable can be null by myself

(3) It depends on what you're trying to do, but I guess that you're trying to implement the Firebase authentication process, in which your user can and should be null before authenticating. Therefore, your function should accept a nullable user value (User?). In there, we do the usual null check and we add a ! operator to promote its value in case user is not null. As aforementioned, Dart isn't always able to infer nullability of variables.

MyUser _userFromFirebaseUser(User? user) {
   return user==null ? null : MyUser(userId: user!.uid);
}

Note how using a null-check ! here is perfectly safe, only because you just checked its nullability in the same line (nonetheless, keep a wise-eye when you refactor this).

EDIT. (4) I can't infer where exactly your exception is fired, but since you want to validate your form, then here's my code from a project of mine:

// inside "saveForm()"...
var currentState = this._formKey.currentState;
if (currentState == null)
  return; // this just means something went wrong
if (!currentState.validate()) return; // todo if invalid, handle this, maybe show a snackbar and stuff...

Note how the variable currentState is now promoted to be non-nullable WITHOUT using the null check operator !, which is just good practice (avoid using ! whenever possible, PREFER using null-aware operators, such as ?. or ??, or ?=)

Share:
2,165
Tom Schäfer
Author by

Tom Schäfer

Updated on December 31, 2022

Comments

  • Tom Schäfer
    Tom Schäfer over 1 year

    I got the same problem with null statements (?) in Dart multiple times in different cases. I really hope somebody can help me.

    Just added some lines of code & the error:

    Error:

    The property 'isEmpty' 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 ('!'). here
    

    Here is one of my examples:

    child: MaterialButton(
                              onPressed: () {
                                var currentState = this._formKey.currentState;
                                if (currentState == null) {
                                  return;
                                }
                                if (_formKey.currentState.validate()) {
                                  AuthService.instance.signIn(
                                      email: emailTextEditingController.text,
                                      password:
                                          passwordTextEditingController.text);
                                  if (AuthService.instance
                                          .checkIfUserExists() ==
                                      true) {
                                    Navigator.pushReplacement(
                                        context,
                                        MaterialPageRoute(
                                            builder: (context) => MainMenu()));
                                  } else {
                                    Navigator.pushReplacement(
                                        context,
                                        MaterialPageRoute(
                                            builder: (context) =>
                                                VerifyScreen()));
                                  }
                                }
                              },
    

    Got this error-message again:

    The method 'validate' can't be unconditionally invoked because the receiver can be 'null'.Try making the call conditional (using '?.') or adding a null check to the target ('!').
    

    After I edited the code with a ! to avoid the Null-Statement like:

    singUpUser() {
    if (formKey.currentState!.validate()) {
      setState(() {
        isLoading = true;
      });
    } else {
      return null;
    };
    

    But now i just avoid the error in the code itself, after starting a emulator and testing it, next error appears:

    Null check operator used on a null value
    

    So thats not the right solution...

    If you need more code, just message me.

    Thank you!

    Tom

    • jamesdlin
      jamesdlin over 2 years
      Have you read dart.dev/null-safety/understanding-null-safety? For case 1, you need to check that val is not null before accessing its members. You didn't say what error your got in case 2; for whatever nullable object you're trying to access, you also need to check for null first (and you might also need to use a null-assertion (!) operator too). For case 3, you again didn't say what error you got, but the user != null check is unnecessary since user is not nullable, and since the return type is MyUser and not MyUser?, returning null is not allowed.
    • Tom Schäfer
      Tom Schäfer over 2 years
      In the second case I got the same error. Just edited my post above to make my problem bit more detailed. thanks!
    • jamesdlin
      jamesdlin over 2 years
      For the second case, as I said, you will need both a null-check and a null assertion.
  • Tom Schäfer
    Tom Schäfer over 2 years
    This is some more code from the second example: singUpUser() { if (formKey.currentState.validate()) { setState(() { isLoading = true; }); } }
  • Tom Schäfer
    Tom Schäfer over 2 years
    I am really trying to understand the Null-Thing, but for now i just try to avoid it by removing the '!'; thanks for your help! Do you can help me with the code above?
  • venir
    venir over 2 years
    Hi! Usually what I do in a Form widget (inside a _saveForm() method) is something like var currentState = this._formKey.currentState; and then if (currentState == null) return;. From now on, currentState is promoted to be non-nullable, since it is a local variable. Yeah, at the moment this trick just works for local variables. Otherwise, you should do a ! promotion or a ?. null-aware access to it. Please upvote my answer if it was helpful, thank you.
  • Tom Schäfer
    Tom Schäfer over 2 years
    thanks a lot, but the problem remains; I declared the variable as non-nullable as in your example but after I can't check if the formKey is validate() because of the same error message; edited the code above; thanks for your help!
  • Tom Schäfer
    Tom Schäfer over 2 years
    my goal is to first check if the form recognizes any problems with the text inside the TextFormFields and only if there are no more problems it should start the SignIn() method... does this makes sense in theory?
  • venir
    venir over 2 years
    Hi, I edited my question - I hope it helps! By the way, it makes total sense to do so.
  • Tom Schäfer
    Tom Schäfer over 2 years
    Hi, thanks for your example! I understood the Null-Statements two days ago but I couldn't implement it the correct way.. thanks for your help!