rrousselGit / freezed

Code generation for immutable classes that has a simple syntax/API without compromising on the features.
https://pub.dev/packages/freezed
1.92k stars 236 forks source link

Confusing legacy tag for "Union types and Sealed classes" #1078

Closed MrLightful closed 3 months ago

MrLightful commented 5 months ago

Context

The documentation marks the whole chapter of Union types and Sealed classes as Legacy. It gives an impression that this whole thing should be avoided and be better done in native dart. It gives a note explaining the details, and the case for map/when vs switch is clear and contains accurate reasoning.

Problem

Nevertheless, if I am not mistaken, Union types and Sealed classes themselves are not outdated and are still relevant? It's just map/when should be replaced with switch and alike?

Relevant use-case for union types: parsing json and convert it to a specific model by unionKey.

Solution

Re-structure chapter in the way that block about map/when specifically is noted as legacy, but not union types as a whole.

Additional context

As of Dart 3, Dart now has built-in pattern-matching using sealed classes. As such, you no-longer need to rely on Freezed's generated methods for pattern matching. Instead of using when/map, use the official Dart syntax.

MrLightful commented 5 months ago

I can imagine it's me missing a common way to replace this functionality with dart-native, but I doubt it. My unionKey example--and especially unionValueCase extra (which is super useful)--is quite an extra utility that is not supported by dart from the box.

adriank commented 3 months ago

In my opinion, labeling freezed unions as "legacy" in the documentation is misleading. Dart sealed classes lack features like copyWith and other utilities generated by freezed. For example:

@freezed
sealed class A with _$A {
  const factory A.something({
    required String s,
  }) = ASomething;

  const factory A.somethingElse({
    int? i,
  }) = ASomethingElse;
  factory A.fromJson(Map<String, dynamic> json) => _$AFromJson(json);
}

can be used like this:

   return switch (a){
     ASomething() => throw UnimplementedError(),
     ASomethingElse() => throw UnimplementedError(),
   };

If not all cases are included, we'll get an error.

On the other hand, Dart's sealed classes only provide pattern matching, but lack features like toJson, immutability, equality check, and other benefits of freezed's code generation. I don't think that freezed could be added to sealed subclasses, because they freezed doesn't work with non-generated superclasses.

Therefore, I believe that either "legacy" word should be removed, or there should be an example of how to use sealed classes with freezed models so that freezed functionality is preserved.

@rrousselGit

rrousselGit commented 3 months ago

It's just map/when that's legacy. Unions are still supported.

adriank commented 3 months ago

Any chance for change in docs? Currently, it says:

(Legacy) Union types and Sealed classes

Should be

Union types and Sealed classes (Legacy) Using pattern matching to read non-shared properties

rrousselGit commented 3 months ago

Sure, feel free to make a PR