Dart: Which is a better practice? Using 'late' or constructor initializer list

2,431

Neither.

Use a default constructor that initializes the fields themselves and a factory constructor that handles deserializing the json object:

class Favourite {
  final int favouriteId;

  Favourite({required this.favouriteId});

  factory Favourite.fromMap(Map<String, dynamic> map) {
    final favouriteId = json['favouriteId'];
    assert(favouriteId != null && favouriteId is int);
    
    return Favourite(
      favouriteId: favouriteId,
    );
  }
}

The late keyword can be a source of headache if you don't handle it properly, so in general don't use it unless you have to.

Share:
2,431
Cherryholme
Author by

Cherryholme

Updated on December 28, 2022

Comments

  • Cherryholme
    Cherryholme over 1 year

    I am modelling a Dart class with the new null safety types in mind. I believe there are two effective ways to initialize non-nullable properties, calculated from a parameter.

    For this example, we will use the Favourite class.

    This class uses the initializer list in the constructor.

    class Favourite {
      int favouriteId;
    
      Favourite({required this.favouriteId});
    
      Favourite.mapFromJson(dynamic json)
          : this.favouriteId = json["favouriteId"];
    }
    
    

    This class uses the 'late' keyword.

    class Favourite {
      late int favouriteId;
    
      Favourite({required this.favouriteId});
    
      Favourite.mapFromJson(dynamic json) {
        this.favouriteId = json["favouriteId"];
      }
    }
    
    

    When would you use one over the other? Using 'late' feels risky. If I added another named constructor, the compiler would not complain about 'favouriteId' not being initialized.

    Are there other options?

    Thank you!

    • Andrej
      Andrej over 3 years
      As far as I know, you should use the late keyword only when you really have to. So the constructor initializer list would be a better option.
  • Cherryholme
    Cherryholme over 3 years
    I am glad to hear that the 'late' keyword is not the option. The code did not feel robust. I tried this factory example, and it works, but I don't understand why. Why is Dart happy with the factory now? It is no longer complaining about 'favouriteId' not being initialized. If you have sources that explain this, I'd love to read it!
  • rmtmckenzie
    rmtmckenzie over 3 years
    A factory method is essentially a static method with slightly better syntax and some properties like using the class's generics & replacing an implicit constructor. Since those aren't needed you could easily write the above as static Favourite mapFromJson(Map<String, dynamic> map) { ... }.
  • Abion47
    Abion47 over 3 years
    @rmtmckenzie I always prefer factory constructors over static "factory" methods if for no other reason than it makes the intention clear. Also, a factory constructor named fromMap will make it that much easier to make this class support deserialization via the json_serialization package if that becomes necessary.
  • Abion47
    Abion47 over 3 years
    Marking a dynamic as nullable is redundant.
  • rmtmckenzie
    rmtmckenzie over 3 years
    @Abion47 oh definitely - sorry I was unclear, that wasn't an argument against them, just trying to clarify what they were.