0

Why does the spread operator in Dart do not clone nested maps? This example shows that the "nested" map on both clones is referring to the same object.

    test("test map", () {
      // Define sourceA
      var sourceA = {
        "nested": {
          "value": 10
        }
      };

      // Define sourceB
      var sourceB = {
        "sourceA": {...sourceA}
      };

      // Clone both sources into two new maps
      var m1 = {...sourceA};
      var m2 = {...sourceB};

      print(m2["sourceA"]!["nested"] == m1["nested"]); // prints true

      // Check hash codes
      print(m2["sourceA"]!["nested"].hashCode); // prints 480486640
      print(m1["nested"].hashCode);             // prints 480486640

      // Change the nested value of m2
      m2["sourceA"]!["nested"]!["value"] = 11;

      // Observe it has been changed in m1
      print(m1["nested"]!["value"]); // prints 11
    });

What I am trying to achieve is to be able to change nested properties on one of the clones only.

artberry
  • 791
  • 2
  • 7
  • 18
  • 1
    "Why does the spread operator in Dart do not clone nested maps?" Dart does not have copy constructors, and therefore it does not know how to create copies of arbitrary objects. You maybe could argue that `List`, `Map`, and `Set` could be handled as special cases, but I think it would be confusing if copying a collection copied some objects but not others. – jamesdlin Mar 18 '22 at 06:43

1 Answers1

1

The Spread operator copies the collection with their reference aka Shallow copy. To read more about the differences between Shallow vs Deep copy, you can read here. This is quite common in many languages.

There are different ways you can do a deep copy in Dart. Here is an example based on your code:

import 'dart:convert';

main(){
  // Define sourceA
      var sourceA = {
        "nested": {
          "value": 10
        }
      };

      // Define sourceB
      var sourceB = {
        "sourceA": {...sourceA}
      };
  

      // Clone both sources into two new maps
      var m1 = {...sourceA};
      var m2 = {...sourceB};
      var m3 = json.decode(json.encode(sourceB)); // deep copy

      print(m2["sourceA"]!["nested"] == m1["nested"]); // prints true
      print(m3["sourceA"]!["nested"] == m1["nested"]); // prints false

      // Check hash codes
      print(m2["sourceA"]!["nested"].hashCode); // prints 418854379
      print(m3["sourceA"]!["nested"].hashCode); // prints 892131505
      print(m1["nested"].hashCode);             // prints 418854379

      // Change the nested value of m3
      // m2["sourceA"]!["nested"]!["value"] = 11;
      m3["sourceA"]!["nested"]!["value"] = 11;

      // Observe it has been changed in m1
      print(m1["nested"]!["value"]); // prints 10
}
Majid
  • 2,507
  • 2
  • 19
  • 18