1

Firstly, I have two models like this:

class Task {
final int id;
final String title;
final List<User> users;
}

class User {
final int id;
final String name;
}

I have the original Task object let call it A, and I make a copy called B so that I can reset B to A if user make a mistake and wants to retrieve the original one. Here is the copy :

Task a = Task(
    id:0,
    title: 'Task 1',
    users: [
        User(
            id:1,
            name: 'John',
        ),
    ],
);

Task b = Task(
    id: a.id,
    title: a.title,
    user: List<User>.from(a.users),
);
 

When I update b.id and b.title there is no problems, if I reset my object it come back to a data.

But if I update the user name of user with the id 1 on B, it updates the user on A. I don't understand why ?

rigorousCode
  • 385
  • 1
  • 2
  • 9
  • I think, [Is there a way to pass a primitive parameter by reference in Dart?](https://stackoverflow.com/q/18258267/10157127) answer your question. – Md. Yeasin Sheikh Feb 27 '22 at 13:36
  • You cannot copy a custom class that way, even less a list of them. You're only copying references which is why you get this result. There is a discussion on how to overcome this here: https://stackoverflow.com/questions/13107906/how-can-i-clone-an-object-deep-copy-in-dart – ManuH68 Feb 27 '22 at 14:30
  • add `new` in front of user list in b – Lars Feb 27 '22 at 14:57
  • new doesn't work and other posts unfortunately doesn't helped me – rigorousCode Feb 27 '22 at 15:10
  • @lrsvmb `new` is not necessary and will not change anything. – jamesdlin Feb 27 '22 at 16:48

1 Answers1

1

The scenario you describe is not possible with the code that you've posted. You claim:

But if I update the user name of user with the id 1 on B, it updates the user on A.

but your User class declaration contains only final members of immutable types, so it is not possible to modify a User object. The code you've posted also omits explicit constructors for your classes.

Assuming that you don't actually have final members: Your problem is that although b is a new Task object that copies the members of a, it is not a deep copy. b.users copies of the a.users List itself but not the List elements. The a.users and b.users Lists thus refer to the same User objects.

There is no automatic way to make copies (much less deep copies). You would need to do something like:

class User {
  int id;
  String name;

  User({required this.id, required this.name});

  User clone() => User(
        id: id,
        name: name,
      );
}

class Task {
  int id;
  String title;
  List<User> users;

  Task({required this.id, required this.title, required this.users});

  Task clone() => Task(
        id: id,
        title: title,
        users: [
          for (var user in users) user.clone(),
        ],
      );
}
jamesdlin
  • 81,374
  • 13
  • 159
  • 204