How to clone (copy values) a complex object in Dart 2

With the classes you have shown us here, there is nothing shorter than

Person p2 = Person()
  ..name = p1.name
  ..surname = p1.surname
  ..city = (City()..name = p1.city.name..state = p1.city.state);

If you add a clone method to Person and City, then you can obviously use that. There is nothing built in to the language to allow you to copy the state of an object.

I would recommend changing the classes, at least by adding a constructor:

class Person {
  String name;
  String surname;
  City city;
  Person(this.name, this.surname, this.city);
}
class City {
  String name;
  String state;
  City(this.name, this.state);
}

Then you can clone by just writing:

Person P2 = Person(p1.name, p1.surname, City(p1.city.name, p1.city.state));

(And ob-link about names)

I say that there is no language feature to copy objects, but there actually is, if you have access to the dart:isolate library: Sending the object over a isolate communication port. I cannot recommend using that feature, but it's here for completeness:

import "dart:isolate";
Future<T> clone<T>(T object) {
  var c = Completer<T>();
  var port = RawReceivePort();
  port.handler = (Object o) {
    port.close();
    c.complete(o);
  }
  return c.future;
}

Again, I cannot recommend using this approach. It would work for simple objects like this, but it doesn't work for all objects (not all objects can be sent over a communication port, e.g., first-class functions or any object containing a first class function).

Write your classes to support the operations you need on them, that includes copying.


As said, there is no built in solution for that, but if the ideia is to accomplish immutable value types you can check built_value.

https://medium.com/dartlang/darts-built-value-for-immutable-object-models-83e2497922d4


My simpler solution just let clone() return a new Person with the current values:

class Person {
  String name;
  String surname;
  City city;
  Person(this.name, this.surname, this.city);
  clone() => Person(name, surname, city);
}

You might further need to recursively clone the objects in your Person. as an example by creating a similar clone() function in the City and using it here as city.clone().
For the strings you will need to check their behavior or also create / add a way for cleaning them.


I noted that using Map.from() do a shallow copy and not a deep copy.

To do a deep copy of a class containing a Map of anoter Class, one solution can be to use a nammed constructor

class MyClassB {
   int myVar;
   
   // Constructor
   MyClassB(this.id);
   
   // Named Constructor to do a deep clone
   MyClassB.clone(MyClassB b){
     id = b.id;
   }
}

class MyClassA { 
  Map<int,MyClassB> mapOfClassB;

  // Constructor
  MyClassA(this.myClassB)

  // Named constructor to do a deep clone
  MyClassA.clone(MyClassA a){
    Map<int,myClassB> m = {};
    myClassB  = a.mapOfClassB.forEach((k,v)=> m[k] = MyClassB.clone(v)); // Use the clone constructor here, if not the maps in MyClassA and MyClassB will be linked
  }
}

main() {
  var b1 = MyClassB(20);
  var a1 = MyClassA({0:b1});
  
  var a2 = MyClass1A.clone(a1);
  
  a2.mapOfClassB[0].id = 50;
  
  print(a1.mapOfClassB[0].id); // Should display 20
  print(a2.(a1.mapOfClassB[0].id) // Should display 50 
}

Tags:

Dart