Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BuiltValue deprecation #1164

Open
subzero911 opened this issue Jun 16, 2022 · 4 comments
Open

BuiltValue deprecation #1164

subzero911 opened this issue Jun 16, 2022 · 4 comments
Assignees
Labels

Comments

@subzero911
Copy link

subzero911 commented Jun 16, 2022

BuiltValue should be deprecated, because Freezed does the same stuff and more, and much easier and more concise.
It was a good choice in 2018, but now it's undesirable for beginners to drag this outdated package into the modern projects.

BuiltValue has a strange ugly syntax with numerous getters and annotations:

abstract class Person implements Built<Person, PersonBuilder> {
  static Serializer<Person> get serializer => _$personSerializer;

  // Can never be null.
  int get id;

  @nullable
  int get age;

  @nullable
  @BuiltValueField(wireName: 'first_name')
  String get firstName;

  @nullable
  BuiltList<String> get hobbies;

  Person._();
  factory Person([void Function(PersonBuilder) updates]) = _$Person;
}

While Freezed syntax is intuitive and much less verbose:

@freezed
class Person with _$Person {
  const factory Person({
    required String firstName,
    required String lastName,
    required int age,
  }) = _Person;
}

Also it's great for BLoC states declaration:

@freezed
class Union with _$Union {
  const factory Union.data(int value) = Data;
  const factory Union.loading() = Loading;
  const factory Union.error([String? message]) = Error;
}

BuiltValue also has a cumbersome copying through the Builder pattern:

var structuredData = new Account((b) => b
    ..user.update((b) => b
        ..name = 'John Smith')
    ..credentials.phone.update((b) => b
        ..country = Country.us
        ..number = '555 01234 567')
    ..node.left.left.left.account.update((b) => b
        ..user.name = 'John Smith II'
        ..user.nickname = 'Is lost in a tree')
    ..node.left.right.right.account.update((b) => b
        ..user.name = 'John Smith III'));

While Freezed supports a familiar copyWith method

newCompany = company.copyWith.director(name: 'John Doe');

You could continue supporting it, but I suggest you putting the statement "Prefer choosing Freezed" on a main page.

@davidmorgan davidmorgan self-assigned this Jun 16, 2022
@davidmorgan
Copy link
Collaborator

Thank you for your input.

In general I agree with the idea of reducing the number of competing packages.

I'm well aware of the compromises made in built_value's design and so I've watched freezed with interest.

I agree that freezed is better for simple use, but I think built_value is better for complex use. By that I mean, deeply nested and complex data models. It's unfortunate that we don't have one package that is equally strong on both--but nobody has come up with a way to do it yet.

Perhaps simple projects should prefer freezed; but they might grow into complex projects and wish they had started with built_value. So, I don't think there is a clear recommendation to be given.

The example with structuredData shows exactly the difference. When you write left.right.right you are digging in to nested builders; it is exactly the more complex approach that built_value takes that lets you do a complex update in a simple way. The equivalent update with freezed would be much more cumbersome.

I also think now is not the right time to push for a single winning package on this. The Dart team is working on

https://github.com/dart-lang/language/blob/master/working/macros/feature-specification.md

which will mean that both built_value and freezed can be significantly improved. So, I suggest waiting for that to land then re-evaluating.

BTW, another consideration is JSON serialization. I know freezed can be used with json_serializable. The comparison there to built_value is similar. For simple data models, json_serializable works. For nested models with polymorphism and generics, you will find much more success with built_value. Again, it doesn't seem like there is a way to choose definitely between them--except that if you know you will have a complex data model then perhaps you should understand the differences carefully before picking which to use.

Thanks.

@chickenblood
Copy link

We should also remember that "freezed" is not a real word and that it should be called "frozen" :D

@felix-ht
Copy link

Just my two cents:

I have experience with both freezed and built_value. Currently, we use built_value in a large project with very deep nesting. The support for deeply nested, complex, and immutable objects and collections is a unique feature of this package.

This is particularly beneficial if you need to maintain complex but immutable state. For example, consider a complex BLoC state where users are stored in a BuiltMap<String, User>. You can easily expose this entire state without worrying about modifications or creating copies of internal mutable maps.

Using this library makes this straightforward. Yes there is some overhead setting up built_value classes, but this extra effort is well worth it because you will be spending much more of time "modifying" these object than creating the shell classes. (And if you want to have cleaner constructors you can just create a factory method).

In summary: Although the builder pattern might seem complex initially, it is actually very elegant for rebuilding complex objects.

@davidmorgan
Copy link
Collaborator

Thanks Felix! Always great to hear it's working as intended for someone :)

I mentioned macros upthread, as it happens I have since joined the Dart language team[1] and I'm part of the group working on macros. We're in touch with the author of freezed and he's already experimented with the work in progress APIs. I look forward to seeing what happens in this space when macros launch :)

[1] I was already at Google and working on Dart, but on Google-internal things rather than the language team.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants