Search code examples
flutterdart

What does assert do in Dart?


I'm curious about the purpose of using assert in Dart programming. Despite researching on my own, I haven't been able to understand it fully. It would be very helpful if someone could provide an explanation for the use of assert in Dart.


Solution

  • Main purpose of assert is testing conditions during debugging/development.

    Let's think about this example:

    class Product {
      Product({
        required this.id,
        required this.name,
        required this.price,
        this.size,
        this.image,
        this.weight,
      })  : assert(id > 0),
            assert(name.isNotEmpty),
            assert(price > 0.0);
    
      final int id;
      final String name;
      final double price;
      final String? size;
      final String? image;
      final int? weight;
    }
    

    We have a Product class and fields like id, name and price are mandatory, but other fields can be handled by generic values, as you guess. By asserting required fields, you'll test this data class during debugging/development. Keep in the mind, all asserts are ignored in release/production mode;

    From the dart.dev#assert:

    In production code, assertions are ignored, and the arguments to assert aren’t evaluated.

    Comparing to writing tests, even though they are not the same thing, asserts can be very handy with minimal effort, so be generous for writing asserts, especially if you don't write tests, it always rewards you.

    Since constants like kDebugMode, kReleaseMode are part of package:flutter/foundation.dart, another use case is debugMode specific codes in Non-Flutter applications. Let's have a look at this code:

    bool get isDebugMode {
      bool value = false;
      assert(() {
        value = true;
        //you can execute debug-specific codes here
        return true;
      }());
      return value;
    }
    

    At first it may look confusing, it's a tricky yet simple code. An anonymous closure always returns true, so we don't throw any exception in any case. Since the compiler eliminates the assert statements in release mode, that closure only runs in debug mode and mutates the value variable.

    When debugging, you can also extend the use cases like this example, from Flutter source code:

    void addAll(Iterable<E> iterable) {
      int i = this.length;
      for (E element in iterable) {
        assert(this.length == i || (throw ConcurrentModificationError(this)));
        add(element);
        i++;
      }
    }
    

    Again, exception is only thrown in debug mode and you can now distinguish the violation more easily.

    Nullable Example

    For the versions of Dart before 2.12, your typical example should be look like this:

    import 'package:meta/meta.dart';
    
    class Product {
      final int id;
      final String name;
      final int price;
      final String size;
      final String image;
      final int weight;
    
      const Product({
        @required this.id,
        @required this.name,
        @required this.price,
        this.size,
        this.image,
        this.weight,
      }) : assert(id != null && name != null && price != null);
    }