schultek / dart_mappable

Improved json serialization and data classes with full support for generics, inheritance, customization and more.
https://pub.dev/packages/dart_mappable
MIT License
164 stars 23 forks source link

`copyWith` missing optional parameter of abstract class with polymorphism #215

Closed samfeng0517 closed 3 months ago

samfeng0517 commented 3 months ago

Description

If I have a polymorphism like this:

import 'package:dart_mappable/dart_mappable.dart';

part 'animal.mapper.dart';

@MappableClass(
  discriminatorKey: 'name',
  includeSubClasses: [Cat, Dog],
)
abstract class Animal with AnimalMappable {
  final String name;
  final String? sound;
  final bool isAlive;

  const Animal({
    required this.name,
    required this.isAlive,
    this.sound,
  });

  Animal updateSound(String sound) => copyWith(
        sound: sound,
        isAlive: true,
      );
}

@MappableClass(
  discriminatorValue: 'cat',
)
class Cat extends Animal with CatMappable {
  String color;

  Cat(this.color, {required super.isAlive}) : super(name: 'cat');
}

@MappableClass(
  discriminatorValue: 'dog',
)
class Dog extends Animal with DogMappable {
  int age;

  Dog(this.age, {required super.isAlive}) : super(name: 'dog');
}

I'd expect that Animal's copyWith will have an optional parameter 'sound' that I can assign. However it will tell you that sound is not exist.

Expected Behavior

Get a copyWith that have optional parameter

Actual Behavior

Only have non optional parameter

Screen shoot

image
schultek commented 3 months ago

Thanks for this well written issue.

The behavior is expected though, and here's why:

When you call .copyWith on an instance of Dog the implementation calls the Dog constructur. Because that one doesn't have the sound parameter, the copyWith function doesn't have the sound parameter. Now since the Dogs copyWith has to override the inherited Animals copyWith, that one also can't have the sound parameter, or there would be no valid override.

So generally a superclasses copyWith method only has parameters that also all subclasses have in their constructors.

Therefore you can fix it by adding the sound parameter to both Dog and Cat constructors.