9

In nullsafety.dartpad.dev if I write the following code:

void main() {
  String? name = 'Bob';
  print(name.length);
}

I get the following compile-time error:

An expression whose value can be 'null' must be null-checked before it can be dereferenced

And the following runtime error:

Property 'length' cannot be accessed on 'String?' because it is potentially null.

The Type promotion on null checks documentation says:

The language is also smarter about what kinds of expressions cause promotion. An explicit == null or != null of course works. But explicit casts using as, or assignments, or the postfix ! operator we’ll get to soon also cause promotion. The general goal is that if the code is dynamically correct and it’s reasonable to figure that out statically, the analysis should be clever enough to do so.

Question

There is no possible way name could be null in the code above. The documentation also says assignments should cause type promotion. Am I misunderstanding type promotion or is this a bug in DartPad?

Clarification

Since a couple of the answers are providing workaround solutions to the error messages, I should clarify that I'm not trying to solve the coding problem above. Rather, I'm saying that I think the code should work as it it. But it doesn't. Why not?

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
  • 1
    Not sure if it's actually a bug(or if it would be a bug just with dartpad or the actual sdk), but it's certainly odd because if you do `name = "test";` right before the `print`, the error disappears. – Christopher Moore Aug 22 '20 at 01:08
  • 4
    That code is actually going to work when null safety is released. Initializing assignments are going to promote the same way as other assignments, and the type of the variable (and it's non-nullable pendant) are considered "types of interest" (which means that assignment to those will promote, not any old assignment promotes because that can cause undesired promotions). – lrn Aug 22 '20 at 18:42
  • @lrn, thank you for that confirmation. I understood the first part of your answer but have a couple questions about the second part. First, what is the meaning of "pendant"? Second, what would an undesirable promotion be? – Suragch Aug 23 '20 at 05:53
  • For "pendant", read "counterpart" (I was directly translating a non-English idiom into English).. An undesirable promotion would be, fx, `Widget widget = SomeWidget(); var widgetList = [widget]; widgetList.add(OtherWidget());`. If we promote `widget` to `SomeWidget`, we'd also make the list a `List`, even though we aren't actually interested in that. You have to show that you are interested in the particular subtype for assignment promotion to apply, fx by doing an `is` check for the type or its nullable/non-nullable counterpart. The counterpart of the declared type is interesting. – lrn Aug 23 '20 at 07:51
  • @lrn, Ah, I thought promotion only referred to promoting a nullable type to its non-nullable counterpart. I see from your description that it can mean other subtypes as well. – Suragch Aug 23 '20 at 08:08

2 Answers2

5

This answer is in response to the bounty that was added to the original question. The bounty reads:

Please explain how String? is different from String and how type promotion works in Dart.

String? vs String

The type String? can contain a string or null. Here are some examples:

String? string1 = 'Hello world';
String? string2 = 'I ❤️ Dart';
String? string3 = '';
String? string4 = null;

The type String, on the other hand, can only contains strings (once null safety is a part of Dart, that is). It can't contain null. Here are some examples:

String string1 = 'Hello world';
String string2 = 'I ❤️ Dart';
String string3 = '';

If you try to do the following:

String string4 = null;

You'll get the compile-time error:

A value of type 'Null' can't be assigned to a variable of type 'String'.

The String type can't be null any more than it could be an int like 3 or a bool like true. This is what null safety is all about. If you have a variable whose type is String, you are guaranteed that the variable will never be null.

How type promotion works

If the compiler can logically determine that a nullable type (like String?) will never be null, then it converts (or promotes) the type to its non-nullable counterpart (like String).

Here is an example where this is true:

void printNameLength(String? name) {
  if (name == null) {
    return;
  }
  print(name.length);
}

Although the parameter name is nullable, if it actually is null then the function returns early. By the time you get to name.length, the compiler knows for certain that name cannot be null. So the compiler promotes name from String? to String. The expression name.length will never cause a crash.

A similar example is here:

String? name;
name = 'Bob';
print(name.length);

Although name is nullable here, too, the string literal 'Bob' is obviously non-null. This also causes name to be promoted to a non-nullable String.

The original question was regarding the following:

String? name = 'Bob';
print(name.length);

It seems that this should also promote name to a non-nullable String, but it didn't. As @lrn (a Google engineer) pointed out in the comments, though, this is a bug and when null safety comes out, this will also work like the previous example. That is, name will be promoted to a non-nullable String.

Further reading

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
0

I understand what you are saying. Try this out.

enter image description here

In order for type promotion to work you must first confirm that the value is not null as the documentation says.

As you can see in the picture dart is able to do the type promotion or understand that name is not going to be null because it checks that on the if statement beforehand.

But if using it outside the if statement without checking if it is not null beforehand, dart knows it can be assigned null anytime again. That’s why it encourages always checking if it is null. Because any instatiated variable ( a variable with a value assigned) can be assigned null in the future.

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
Marte
  • 1
  • 1
  • 1
    The OP also isn't asking for a solution to the error. They are trying to understand type promotion. The docs say an assignment is an explicit cast, yet doing so at the same time as declaration creates an error. – Christopher Moore Aug 22 '20 at 01:16
  • yeah! I know. I am answering based in de dart docs: Dart promotion on null check says the following about type promotion: But if the value isn’t null, it would be good to be able to move it over to the non-nullable side so you can call methods on it. Flow analysis is one of the primary ways to do this for local variables and parameters. We’ve extended type promotion to also look at == null and != null expressions. If you check a variable with nullable type to see if it is not null, Dart then promotes the variable to the underlying non-nullable type. – Marte Aug 23 '20 at 14:11
  • Look at the docs the OP quotes. They are fully aware of this already. They are trying to understand why their code does not promote even though the docs imply it should. – Christopher Moore Aug 23 '20 at 14:19