skip to Main Content

I have the code

if (WORDLIST[language]==null) throw new Exception("Invalid Language");
List<String> wordlist = WORDLIST[language];

the compiler says

Error: A value of type ‘List?’ can’t be assigned to a variable of type ‘List’ because ‘List?’ is nullable and ‘List’ isn’t.

However its both not possible in my code for language to be set to a value that is not valid and just to be safe there is the exception thrown if it gets called somewhere without checking the language exists. How can I get the compiler to recognize this is valid?

Full Code is here(though the exception was added afterwards to try and handle new compiler):
https://github.com/mctrivia/bip39-multi/blob/mctrivia-patch-1/lib/src/bip39_multi_base.dart#L80

3

Answers


  1. One way to hint to the compiler is to add an else clause, that way the compiler is sure the else branch will only execute when WORDLIST[language]!=null.

    if (WORDLIST[language]==null) throw new Exception("Invalid Language");
    else List<String> wordlist = WORDLIST[language];
    
    Login or Signup to reply.
  2. Map.operator [] returns a nullable type, period. The compiler doesn’t know what WORDLIST[language] will return at runtime; it doesn’t know that WORDLIST isn’t some Map implementation that returns different values each time operator [] is called. This is the same reason why only local variables can be type promoted.

    The typical ways to fix this are:

    • Use ! to force the result to be non-nullable:
      if (WORDLIST[language]==null) throw new Exception("Invalid Language");
      List<String> wordlist = WORDLIST[language]!;
      
    • Use a local variable:
      var result = WORDLIST[language];
      if (result == null) throw new Exception("Invalid Language");
      List<String> wordlist = result;
      

      Since wordlist is probably already a local variable, you also could just reorder your code:

      List<String>? wordlist = result;
      if (wordlist == null) throw new Exception("Invalid Language");
      // wordlist is now type-promoted to be List<String>.
      
    Login or Signup to reply.
  3. The compiler is not smart enough to promote general expressions, only local variable can be promoted.

    When you write if (WORDLIST[language] == null) throw ..., that doesn’t actually make the compiler any wiser wrt. the following WORDLIST[language] expression.
    It takes specific knowledge about the implementation of the [] operator of WORDLIST to guarantee that it returns the same value every time it’s called with the same argument. The compiler does not assume to have such knowledge.

    What you should do is:

    List<String>? wordlist = WORDLIST[language];
    if (wordlist == null) {
      throw ArgumentError.value(language, "language", "Invalid language");
    }
    // use `wordlist` as `List<String>` here.
    

    By assigning the value to a local variable, you allow the test+throw to promote that variable to non-nullable in the following (implicit else-branch) code.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search