title: Inheritance in Null Safety - Flutter
body: <p>I'm working on Flutter Clean Architecture. Initially I developed my project without sound null-safety. I recently migrated it to null-safety.</p>
  <p>Migrating to null-safety was pretty smooth but unfortunately there is an issue with inheriting classes that I'm unable to resolve.</p>
  <p>Here is a sample of my code I'm working with:</p>
  <p><strong>ENTITIES:</strong></p>
  <p><strong>UserEntity:</strong></p>
  <pre><code>class UserEntity extends Equatable {
      final int userID;
      final String email;
  
      const UserEntity({required this.userID, required this.email});
  
      @override
      List&lt;Object&gt; get props =&gt; [userID, email];
  }
  </code></pre>
  <p><strong>CourseEntity:</strong></p>
  <pre><code>class CourseEntity extends Equatable {
      final int courseID;
      final String courseName;
  
      const CourseEntity({required this.courseID, required this.courseName});
  
      @override
      List&lt;Object&gt; get props =&gt; [courseID, courseName];
  }
  </code></pre>
  <p><strong>DataEntity:</strong></p>
  <pre><code>class DataEntity extends Equatable {
      final UserEntity? user;
      final CourseEntity? course;
  
      const DataEntity({required this.user, required this.course});
  
      @override
      List&lt;Object&gt; get props =&gt; [user, course];
  }
  </code></pre>
  <p><strong>MODELS:</strong></p>
  <p><strong>UserModel:</strong></p>
  <pre><code>class UserModel extends UserEntity {
      const UserModel({
          required int userID,
          required String email,
      }) : super(userID: userID, email: email);
  
      factory UserModel.fromJson(Map&lt;dynamic, dynamic&gt; json) {
          return UserModel(
              userID: json[&quot;userID&quot;],
              email: json[&quot;email&quot;],
          );
      }
  
      Map&lt;String, dynamic&gt; toJson() {
          return {
              &quot;userID&quot;: userID,
              &quot;email&quot;: email,
          };
      }
  }
  </code></pre>
  <p><strong>CourseModel:</strong></p>
  <pre><code>class CourseModel extends CourseEntity {
      const CourseModel({
          required int courseID,
          required String courseName,
      }) : super(courseID: courseID, courseName: courseName);
  
      factory CourseModel.fromJson(Map&lt;dynamic, dynamic&gt; json) {
          return CourseModel(
              courseID: json[&quot;courseID&quot;],
              courseName: json[&quot;courseName&quot;],
          );
      }
  
      Map&lt;String, dynamic&gt; toJson() {
          return {
              &quot;courseID&quot;: courseID,
              &quot;courseName&quot;: courseName,
          };
      }
  }
  </code></pre>
  <p><strong>DataModel:</strong></p>
  <pre><code>class DataModel extends DataEntity {
      const DataModel({
          required UserModel? user,
          required CourseModel? course,
      }) : super(user: user, course: course);
  
      factory DataModel.fromJson(Map&lt;dynamic, dynamic&gt; json) {
          return DataModel(
              user: UserModel.fromJson(json[&quot;user&quot;]),
              course: CourseModel.fromJson(json[&quot;course&quot;]),
          );
      }
  }
  </code></pre>
  <p><strong>LOCAL DATASOURCE:</strong></p>
  <p><strong>Saving Data Locally:</strong></p>
  <pre><code>abstract class LocalDataSource {
      Future&lt;void&gt; saveData(DataModel model);
      Future&lt;void&gt; saveUser(UserModel user);
      Future&lt;void&gt; saveCourse(CourseModel course);
  }
  
  class LocalDataSourceImpl implements LocalDataSource {
      @override
      Future&lt;void&gt; saveData(DataModel model) async {
          await saveUser(model.user);
          await saveCourse(model.course);
      }
  
      @override
      Future&lt;void&gt; saveUser(UserModel model) async {
          final box = await Hive.openBox(&quot;USER&quot;);
  
          return box.put(&quot;user&quot;, model.toJson());
      }
  
      @override
      Future&lt;void&gt; saveCourse(CourseModel model) async {
          final box = await Hive.openBox(&quot;COURSE&quot;);
  
          return box.put(&quot;course&quot;, model.toJson());
      } 
  }
  </code></pre>
  <p><strong>Explanation:</strong></p>
  <p>I hope all the sample classes are easy to understand.
  There are 2 entities User and Course. The Data entity is a combination of these 2 entities. The models are extending these entities which means that the entities are the parent classes for their respective models.</p>
  <p>The class LocalDataSource is used to store data locally on the device. I'm using Hive to cache the data. There are 2 main futures namely saveUser and saveCourse. The saveData future is the combination of these 2 futures just like the entities.</p>
  <p><strong>Problem:</strong></p>
  <p>The problem exists in the future saveData of class LocalDataSourceImpl. The future requires 1 argument i.e. DataModel. The other futures also require 1 argument i.e. UserModel and CourseModel.</p>
  <p>In <code>saveData(model)</code> future, when I provide the values for respective arguments to <code>saveUser</code> and <code>saveCourse</code> as <code>saveUser(model.user)</code> and <code>saveCourse(model.course)</code>, this is the error that I receive on arguments passed:</p>
  <blockquote>
  <p>The argument type 'UserEntity' can't be assigned to the parameter type 'UserModel'.dart(argument_type_not_assignable)</p>
  </blockquote>
  <p><strong>Workarounds:</strong></p>
  <p>First workaround could be using getters:</p>
  <pre><code>class DataModel extends DataEntity {
      final UserModel? _user;
      final CourseModel? _course;
  
      const DataModel({
          required UserModel user,
          required CourseModel course,
      }) : _user = user,
           _course = course, super(
               user: user,
               course: course,
           );
  
      UserModel? get user =&gt; _user;
      CourseModel? get course =&gt; _course;
      ...
  }
  </code></pre>
  <p>Second workaround could be overriding fields:</p>
  <pre><code>class DataModel extends DataEntity {
      final UserModel? user;
      final CourseModel? course;
  
      const DataModel({
          required this.user,
          required this.course,
      }) : super(
               user: user,
               course: course,
           );
  
      ...
  }
  </code></pre>
  <p>I'm confused if any of these 2 is a good practice, because there must be no assignment error as Models are actually the subclasses of Entities.</p>
  <p>Thanks in advance!</p>