Current production copy_with_generator does not honor derivation of classes annotated with CopyWith. This means that given class A (copyWith) derived by class B (also copyWith) when an instance of B is cast to A, calling 'copyWith' will return an instance of class A, losing all of the properties of B.
It's clear this can cause issues unless the developer is cognisant.
My specific use case is where copyWith is used to mutate state in Flutter Bloc applications.
When Blocs are responding to events, every event receives the current state as the bloc-declared archetype state (i.e. MyInitialState). The the event handler will cast the state to the class that it is aware of - even though it may currently be an instance of a derived type. When calling "copyWith" all derived values are lost.
Usage
After regenerating your code with this enhancement, add override capabilities to your classes like so:
// ignore_for_file: library_private_types_in_public_api
// required to expose copyWith
@CopyWith()
final class InitialState {
final int id;
final String name;
const InitialState({
required this.id,
required this.name,
});
// classes must now declare the 'copyWith' method like so
_$InitialStateCWProxy get copyWith => _$InitialStateCWProxyImpl(this);
}
@CopyWith()
final class ErroredState extends InitialState {
final String errorMessage;
const ErroredState({
required super.id,
required super.name,
required this.errorMessage,
});
// classes must now declare the 'copyWith' method like so. Note how it declares and returns the proxy for THIS class.
// this is now legal because the enhanced generator declares a inherited relationship between the CWProxy interfaces
@override
_$ErroredStateCWProxy get copyWith => _$ErroredStateCWProxyImpl(this);
}
Effect
Here is a pseudo-code usage example for the above example
InitialState state = ErroredState(id: 1, name: 'name', errorMessage: 'error message');
var newState = state.copyWith(name: 'new name');
print('new state');
// output will be 'ErroredState(id: 1, name: 'new name', errorMessage: 'error message');
Caveats
The PR is indeed a minimal implementation. Some cases not handled are:
Generated code for derived classes will still contain definitions for the supertypes members. These are now redundant, and will produce warnings that they are overrides but do not declare @override. This is benign.
Resolves #87 and #65
Current production copy_with_generator does not honor derivation of classes annotated with CopyWith. This means that given class A (copyWith) derived by class B (also copyWith) when an instance of B is cast to A, calling 'copyWith' will return an instance of class A, losing all of the properties of B.
It's clear this can cause issues unless the developer is cognisant. My specific use case is where copyWith is used to mutate state in Flutter Bloc applications.
When Blocs are responding to events, every event receives the current state as the bloc-declared archetype state (i.e. MyInitialState). The the event handler will cast the state to the class that it is aware of - even though it may currently be an instance of a derived type. When calling "copyWith" all derived values are lost.
Usage
After regenerating your code with this enhancement, add override capabilities to your classes like so:
Effect
Here is a pseudo-code usage example for the above example
Caveats
The PR is indeed a minimal implementation. Some cases not handled are: