flutter inheritance with null safety

452

If I initialize the field within the constructor, I have to call ": super()" with all the needed fields from the inherited class, which results in way too much writing.

That's true only if you modified your constructor to take required arguments. Required arguments naturally prevent derived class's constructors from implicitly calling super() to construct the base class.

In general (i.e., not specifically for the JSON deserialization library you're using), if you don't want to have required arguments for your base class constructor, then you can:

  • Initialize members to non-null default values, either via your constructor's initializer list or by using inline field initializers.

  • Mark the members late. Do this only if you can guarantee that the members will be initialized before they are accessed.

  • Make the members nullable. If you then add null assertions (!) wherever the members are unconditionally accessed, this is equivalent to what your code did before null-safety. (Or add null-checks that fail gracefully.)

Share:
452
DirtyNative
Author by

DirtyNative

Updated on December 31, 2022

Comments

  • DirtyNative
    DirtyNative over 1 year

    I am upgrading my flutter project to null safety support. Inside this project I have abstract model classes and inheritances. They have looked like so:

    abstract class Technology {
      Guid id;
      String name;
      String description;
      String assetName;
    
      Technology();
    
      factory Technology.fromJson(Map<String, dynamic> json) =>
          TechnologyConverter().fromJson(json);
    
      Map<String, dynamic> toJson() => TechnologyConverter().toJson(this);
    }
    
    abstract class Research extends Technology {
      ResearchType researchType;
    
      Research();
    
      factory Research.fromJson(Map<String, dynamic> json) =>
          ResearchConverter().fromJson(json);
    }
    
    class LevelableResearch extends Research {
      LevelableResearch();
    
      factory LevelableResearch.fromJson(Map<String, dynamic> json) =>
          _$LevelableResearchFromJson(json);
      Map<String, dynamic> toJson() => _$LevelableResearchToJson(this);
    }
    

    This was no problem for the build_runner to generate the json serializer. Now as I updated to null safety, I get a lot of errors, starting with "Non-nullable instance field 'id' must be initialized. Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'"

    If I initialize the field within the constructor, I have to call ": super()" with all the needed fields from the inherited class, which results in way too much writing. As the error says, I could mark it with late, but I am not sure if this is the way it should be done.

    What is the correct way to write these classes, so the build_runner can generate a correct json serializer?