MarcelGarus / data_classes

Dart packages that automatically generate data classes for you.
16 stars 1 forks source link

The future of this package #4

Open MarcelGarus opened 5 years ago

MarcelGarus commented 5 years ago

For a new version of the package, I consider completely overhauling the API of this package.

Fundamental problems of this package

So, what's the future of this package? The Dart team actively works on bringing static extension methods and non-nullability by default (NNBD) to Dart. That would allow this package to be even more lightweight and enable a workflow like the following:

Mark your class with an @DataClass() annotation:

@DataClass()
class User {
  final String firstName;
  final String lastName;
  final String? photoUrl;

  const User({
    this.firstName,
    this.lastName,
    this.photoUrl,
  });
}

Because of NNBD the constructor is equivalent to the current one; @required annotations and non-null assertions are no longer needed. The package could then generate the copy, ==, hashCode and toString methods as static extension methods on the User type.

Benefits

Downsides

I'm welcoming any opinions on whether this is a worthy tradeoff.

tvh commented 5 years ago

I like the approach taken by https://pub.dev/packages/sum_types. You could then do the following:

@DataClass
mixin _User {
  String get firstName;
  String get lastName;
  @nullable String get photoUrl;
}

The generated code would then be:

class User with _User {
  const User({
    @required this.firstName,
    @required this.lastName,
    this.photoUrl,
  });
}

When NNBD finally lands one could just replace the @nullable annotations with the new syntax and everything would continue to work.

MarcelGarus commented 5 years ago

Interesting approach! But a possible problem I see with this is that it doesn't work well with generators of other packages, for example hive and json_serializable, because mixins are treated as abstract class and thus can't be instantiated by the generated code.

tvh commented 5 years ago

True, that wouldn't be covered.

If only constructors of extended classes would just call the super class with the same args. It could be so easy:

class User extends _UserBase {
  String get firstName;
  String get lastName;
  @nullable String get photoUrl;
}

abstract class _UserBase {
  String firstName;
  String lastName;
  String photoUrl;

  _UserBase({
    this.firstName,
    this.lastName,
    this.photoUrl,
  });
}

This does compile, but completely forgets the parameters.

skogsbaer commented 5 years ago

We implemented the mixin idea of @tvh in https://github.com/factisresearch/sum_data_types The code in that repo is based on data_classes but the interface is not compatible with data_classes.

skogsbaer commented 5 years ago

Btw: was it intentionally that you use the 4-clause BSD license for data_classes_generator, but BSD 3-clause license for data_classes? It would be easier for us if everything was under BSD 3. Is it possible that you also license the generator part under BSD 3?

MarcelGarus commented 5 years ago

Oh sorry, that was not intentional. To be honest, I didn't pay too much attention to the license clauses. Now I changed both to BSD 3.

MarcelGarus commented 4 years ago

The package could then generate the copy, ==, hashCode and toString methods as static extension methods on the User type.

Oh nooooo, seems like that's not possible. Extensions can't declare members with the same name as a member declared by Object.

MarcelGarus commented 4 years ago

Okay, I re-evaluated the current ecosystem and it seems like there are really cool alternatives in the data class code generation market. There's, of course, built_value by Google, freezed which has some really cool factory constructor syntax to declare fields and others, like hive are thinking about requiring data classes in the future. The freezed package, in particular, does many things right and address the same market like this one. All in all, it's more elegant than this one and makes some bold design decisions (like making the copyWith method not type-safe in order to support nullable fields) that make it more intuitive to use.

So, I've been thinking a bit about the future of this package and I believe the best thing to do is to try to get as close to the vision of this issue as possible: support developers writing their own data classes. There's not much tooling in this regard in the existing ecosystem, so I believe this will be a valuable addition to the Dart community rather than another competing framework.

Here's what this package could offer:

Using this package would look like this:

@DataClass()
class Fruit {
  User({
    @required this.name,
    @required this.color,
    this.amount = 1,
  });

  final String name;
  final Color color;
  final int amount;

  operator ==(Object other) => _$equals(other);
  int get hashCode => _$hashCode;
  String toString() => _$toString();
}

void main() {
  var apple = Fruit(name: 'Apple', color: Colors.red);
  print(apple.toString());
  var badApple = apple.copyWith(color: Colors.brown);
  badApple.hasNoName; // false
}