What does the exclamation mark mean before a function call?

Viewed 19516

I was following a PR for Flutter and came across this code:

if (chunkCallback != null) {
  chunkCallback!(0, 100);
}

What does the exclamation mark mean after chunkCallback? Nothing I search on Google works.

4 Answers

"!" is a new dart operator for conversion from a nullable to a non-nullable type. Read here and here about sound null safety.

Use it only if you are absolutely sure that the value will never be null and do not confuse it with the conditional property access operator.

chunkCallback is a nullable reference to a function.

If you are sure that chunkCallback can't be null at runtime you can "Cast away nullability" by adding ! to it to make compiler happy

typedef WebOnlyImageCodecChunkCallback = void Function(
    int cumulativeBytesLoaded, int expectedTotalBytes);

...

class Class1 {
  final WebOnlyImageCodecChunkCallback? chunkCallback;

  Class1(this.chunkCallback);

  void test() {
    if (chunkCallback == null) {
      throw Exception("chunkCallback is null");
    }

    chunkCallback!.call(0, 100);
  }
}

Esentially, ! in this case is a syntactic sugar for

(chunkCallback as WebOnlyImageCodecChunkCallback).call(0, 100);

The variable chunkCallback must be able to accept null and you cannot call a function on a nullable type without either using ! or ?. This is part of Darts sound null safety

Some great videos on this:

Flutter vid

YouTube vid

Even though the conditional statement checks for null, Dart still requires the exclamation mark before the function call. The difference between using ! over ? is that it will throw an exception instead of using the variable if the value is null.

Some examples:

class Car {
  String? make; // String or null type

  Car([this.make]); // parameter is optional
}

main() {
  Car test = Car('Ford'); // initialised with a value
  Car test2 = Car(); // no value given so null is default

  // returns 4
  if (test.make != null) {
    print(test.make!.length); // ! still needed even though !=null condition stated
  } else {
    print('The value is null');
  }

  // returns The value is null
  if (test2.make != null) {
    print(test2.make!.length);
  } else {
    print('The value is null');
  }
}

Above example shows that conditional check for null is not enough.

And choosing between ? and !

class Customer {
  String? name; 
  String? surname; 

  Customer(this.name, [this.surname]); // constructor with optional parameter []

}

main() {

 Customer ford = Customer('John'); //only name is given a value

 // calling a method on a nullable type doesn't work
 // so ? and ! used here after variable name and before method

 print(ford.name!.length); // operation executed as usual => 4

 print(ford.surname?.length); // ? on null value returns null => null

 print(ford.surname!.length);  // Exception is thrown => TypeError

}
Related