Language: Automatically generate copyWith and copyWithout when class contains only public final fields that are initialized with named arguments.

Created on 13 May 2020  路  7Comments  路  Source: dart-lang/language

Suppose we have a class called Person:

class Person {
  final String name;
  final int age;

  Person({this.name, this.age});
}

Automatically generate the following methods:

Person copyWith({String name, int age}) {
  return Person({
    name: name ?? this.name,
    age: age ?? this.age,
  });
}

Person copyWithout({bool name = false, int age = false}) {
  return Person({
    name: name ? null : this.name,
    age: age ? null : this.age,
  });
}

The copyWith method is like the ones we already know present in flutter plain objects and the copyWithout is the solution I came up with to the problem of not being able to set null value using copyWith (when the user wants to copy something to null he uses the argument with value equal to true. This feature could be a opt in with a decoration in the class, and would have compile time analysis if the class matches the rules described in the title: A class that contains only public final fields that are initialized with named arguments.

The decoration could be something like:

@copyable
class Person {
  final String name;
  final int age;

  Person({this.name, this.age});
}

And the compiler would be able to generate the copyWith and copyWithout methods and also make then available in the autocomplete for good developer experience.

Then with this feature I would be able to do this:

@copyable
class Person {
  final String name;
  final int age;

  Person({this.name, this.age});
}

void main() {
  final person0 = Person(name: 'Person Name', age: 20);
  // name = 'Person Name', age = 20
  final person1 = person0.copyWith(name: 'Another person name');
  // name = 'Another person name', age = 20
  final person2 = person0.copyWithout(age: true);
  // name = 'Person Name', age = null
}

I believe this feature could help a lot in writing tests where we could have some complete filled object (with all fields set to a valid initial value) and wants to change just one field to test a condition. I really hope some sort of copying gets implemented. Because manually writing this methods feels wrong. Thanks in advance!

feature

Most helpful comment

I'd really love for Dart to support the data classes and copy functionality outlined here in this post about C# 9. https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/

I've been building a lot of features in a flutter app recently, and I've found that the community and patterns have coalesced around immutable data types. As a result, we've found oursevles using freezed (https://github.com/rrousselGit/freezed) to provide data classes and "sum types" / "enums with associated data" since there's no story built into Dart for it yet.

The user-land codegen required to support this functionality today makes me sad. It has a lot of quirks and it doesn't interact great with IDEs. It would be game-changing if Dart provided these features out of the box.

All 7 comments

What if Dart add support of Data Classes and this should be part of it?

@pedromassango I dont know exactly how a Data Class you talked about would behave. But if it just classes in the format that I described it could be classified automatically by the compiler without any special keyword.

I don't think this belongs to the language specification. Maybe you could open an issue on the SDK side.

A language-side solution is to implement a parameter spread operator, like JS one, where things like this would be possible:

@copyable
class Person {
  final String name;
  final int age;

  Person({this.name, this.age});
}

void main() {
  final person0 = Person(name: 'Johan', age: 20);
  final person1 = Person(...person0, name: 'Feldispato');
}

This alternative has alredy been proposed (#893, maybe in other issues too).

@pedromassango I dont know exactly how a Data Class you talked about would behave. But if it just classes in the format that I described it could be classified automatically by the compiler without any special keyword.

Sorry. I mean Data classes from Kotlin (https://kotlinlang.org/docs/reference/data-classes.html)

Cf. #125, #183, #314, at least.

Instead of "copyWithout" it would be better to use the following:

void main() {
  var user = User(name: 'Seva');
  print(user.name);
  user = user.copyWith();
  print(user.name);
  user = user.copyWith(name: null);
  print(user.name);
  user = user.copyWith(name: 'Seva2');
  print(user.name);
}

class Unused {
  const Unused();
}

const unused = Unused();

class User {
  final String name;

  User({this.name});

  User Function({String name}) get copyWith => _copyWith;

  User _copyWith({
    Object name = unused,
  }) {
    return User(
      name: name == unused ? this.name : name as String,
    );
  }
}

I'd really love for Dart to support the data classes and copy functionality outlined here in this post about C# 9. https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/

I've been building a lot of features in a flutter app recently, and I've found that the community and patterns have coalesced around immutable data types. As a result, we've found oursevles using freezed (https://github.com/rrousselGit/freezed) to provide data classes and "sum types" / "enums with associated data" since there's no story built into Dart for it yet.

The user-land codegen required to support this functionality today makes me sad. It has a lot of quirks and it doesn't interact great with IDEs. It would be game-changing if Dart provided these features out of the box.

Was this page helpful?
0 / 5 - 0 ratings