Description:

Dart is redesigning its type system to include nullable and non-nullable types. (This is very similar to Kotlin, because of the strict division between nullable and non-nullable types. Kotlin is well positioned to avoid NPE problems). The reason for translating an article like this is to set the stage for our next grammar article on the Dart type system and generics. Because when you go into the Dart type system, you see that it’s actually a loose type system, like the generic variant safety aspect.

Translation Instructions:

Dart Nullability syntax decision: A? [b] or a? .[b]

Original address:Medium.com/dartlang/da…

Original author:Kathy Walrath

Dart is redesigning its type system so that each type has either nullable (expressions of that type can have null values) or non-nullable. We’ll let you know when and how it will be released later this year. Dart will not be null by default, and when you do, you must use special syntax to say that null values are allowed for the current type.

For example, if you want to declare that an integer can be null, you need to add?

int? someInt; // someInt variable can be null
Copy the code

If you’ve seen Kotlin, Swift, or C# code, you might wonder? Grammar is not unfamiliar. But there are some differences – in particular, the subscript ([]) operator, which is often used to access collections and arrays. C# and Swift are both used? [], and Dart(as well as ECMAScript) is currently planned to use? . The [] syntax.

e1? .[e2]// if e1 is null, null is returned; Otherwise, return the value of E1 [e2]
Copy the code

This article will explain the reasons behind the decision and encourage you to have some ideas and suggestions of your own. Much of this is based on Bob Nystrom’s comment on issue #376, which summarizes a discussion between Bob and NNBD specification lead LeafPetersen.

Why dot syntax?

e1? (e2) and e1? [e2] Both approaches have their own advantages.

e1? [e2]:

  • Be consistent with C# and Swift
  • More concise
  • Similar to the!The syntax for the operator (which can be added to an expression to indicate that its value is not null, even if it is nullable) :e1! [e2]

e1.[e2]:

  • Similar to cascading:
e1.. [e2]// the method of cascadinge1? . [e2]// void check cascade method
Copy the code
  • Syntax similar to other nullable checking methods:e1? .e2()
  • This can be naturally extended to other operations
  • Ambiguity can be avoided in the following code:{ e1 ? [e2] : e3 }

We spent a while trying to figure out how to avoid it? [] ambiguity method. The problem is that you can’t tell this this code {e1? [e2] : e3} is a set containing the result of a conditional expression, or a map containing nullable subscript keys.

If we disambiguate the expression by adding parentheses, we can optionally add –{(e1? [e2] : e3)}– you can explicitly think of it as a set. Or we can wrap parentheses around the first part –{(e1? [e2]) : e3)}– you can explicitly think of this as a map collection. But without parentheses, the parser doesn’t know what to do.

There are several solutions to this ambiguity, but none seems to be satisfactory. One way is to rely on Spaces to distinguish between options. In this method, because this space is in? And so you always use E1?[e2] as the first half of the conditional expression. And you always use E1?[e2] as the nullable subscript, because there is no space between the two tags.

In theory, relying on whitespace is not a problem in formatting code. But many users write unformatted Dart code as input to the formatter. Thus, everywhere in the language, such input formats become more sensitive and vulnerable to whitespace. This is rare in Dart so far, which is a nice syntactic feature. (For example –a and –a are both valid but have different meanings

Ignoring the ambiguity issue, there’s another reason to use dot syntax: if we write for other operators (such as E1? .+(e2), etc.) to add a null-detectable form, you may need to use periods.

Another feature we discussed for NNBD is null-checking call syntax. If we don’t need points here, it has the same ambiguity problem:

varwat = { e1? (e2):e3 };// Map or set?
Copy the code

No matter what we do for? What solution does this form give that it must all work equally well?

someJson? [recipes]? [2]? [ingredients]? [pepper]Copy the code

From our point of view, that doesn’t look good. It looks less like a method chain and more like some combination of infix operators – sort of like?? Operator. Compare this with the following code:

someJson? .[recipes]? .2]? .[ingredients]? .[pepper]Copy the code

In this case, it is clearly a chain of method calls. It’s also visually obvious, because the user needs to quickly understand how many expressions are null short.

Summarizing so much, it seems that we should use? [Here are some reasons:

  • It avoids ambiguity. (The lexical analyzer has been converted? .As a single “empty check” token)
  • It naturally extends to calls that can check for null values.
  • It can be extended to other operators that understand null values.
  • It gives Dart a more powerful input language for formatters.
  • It looks customary to call in the method chain.
  • It visually shows how many method chains can be short-circuited.

What do you think?

We always value feedback and suggestions, and the best way to give feedback on this syntax is to comment on language Issue #376 (or like some of the comments). Consider checking out some of the other great language features we’re using before you use them.

You can find more information here:

NNBD:

  • Grammar specification
  • The roadmap
  • The problem

Other changes and features of the Dart language:

  • Language change
  • Process of language evolution
  • Dart Language Description

Translator has something to say

This article is about the nullable syntax for arrays or collections in Dart. [B] or use a? [B]. Then the author gives some reasons why a is used. [B] for the reasons that Another takeaway from this article is that Dart is refactoring its entire type system into nullable and non-nullable types, as Kotlin did, to make the system more complete and rigorous.

The Dart nullable and non-nullable types are experimental, but are already being used in the DART2. x source code.

For example, the source code for ListQueue in DART

//
class ListQueue<E> extends ListIterable<E> implements Queue<E> {
  static const int _INITIAL_CAPACITY = 8;
  List<E? > _table;/ / declare a List < E? > collection, the generic type parameter E is nullable
  int _head;
  int _tail;
  int _modificationCount = 0;

  /// Create an empty queue.
  ///
  /// If [initialCapacity] is given, prepare the queue for at least that many
  /// elements.
  ListQueue([int? initialCapacity])// Declare nullable type int
      : _head = 0,
        _tail = 0,
        _table = List<E? >(_calculateCapacity(initialCapacity));static int _calculateCapacity(int? initialCapacity) {
    // Short-check the nullable type initialCapacity
    if (initialCapacity == null || initialCapacity < _INITIAL_CAPACITY) {
      return _INITIAL_CAPACITY;
    } else if(! _isPowerOf2(initialCapacity)) {return _nextPowerOf2(initialCapacity);
    }
    assert(_isPowerOf2(initialCapacity));
    returninitialCapacity; }... }Copy the code

However, it should be noted that currently it is not directly open to developers, and it is still in the experiment stage.

So, I’m sure that the nullable and non-nullable types in Dart will soon be in formal use, and developers who have studied Kotlin, Swift, or C# will have a better understanding of the Dart type system. With that in mind, we’ll be ready to formally enter the Dart type system in the next installment, where we’ll take a look at optional types, generics, covariant, generic types, and more.

My official account

Welcome to: Mr. Xiong Meow