How can I clone an Object (deep copy) in Dart?
Solution 1
No as far as open issues seems to suggest:
https://github.com/dart-lang/sdk/issues/3367
And specifically:
... Objects have identity, and you can only pass around references to them. There is no implicit copying.
Solution 2
Darts built-in collections use a named constructor called "from" to accomplish this. See this post: Clone a List, Map or Set in Dart
Map mapA = {
'foo': 'bar'
};
Map mapB = new Map.from(mapA);
Solution 3
Late to the party, but I recently faced this problem and had to do something along the lines of :-
class RandomObject {
RandomObject(this.x, this.y);
RandomObject.clone(RandomObject randomObject): this(randomObject.x, randomObject.y);
int x;
int y;
}
Then, you can just call copy with the original, like so:
final RandomObject original = RandomObject(1, 2);
final RandomObject copy = RandomObject.clone(original);
Solution 4
I guess for not-too-complex objects, you could use the convert library:
import 'dart:convert';
and then use the JSON encode/decode functionality
Map clonedObject = JSON.decode(JSON.encode(object));
If you're using a custom class as a value in the object to clone, the class either needs to implement a toJson() method or you have to provide a toEncodable function for the JSON.encode method and a reviver method for the decode call.
Solution 5
Unfortunately no language support. What I did is to create an abstract class called Copyable
which I can implement in the classes I want to be able to copy:
abstract class Copyable<T> {
T copy();
T copyWith();
}
I can then use this as follows, e.g. for a Location object:
class Location implements Copyable<Location> {
Location({
required this.longitude,
required this.latitude,
required this.timestamp,
});
final double longitude;
final double latitude;
final DateTime timestamp;
@override
Location copy() => Location(
longitude: longitude,
latitude: latitude,
timestamp: timestamp,
);
@override
Location copyWith({
double? longitude,
double? latitude,
DateTime? timestamp,
}) =>
Location(
longitude: longitude ?? this.longitude,
latitude: latitude ?? this.latitude,
timestamp: timestamp ?? this.timestamp,
);
}
Related videos on Youtube
george koller
Updated on May 07, 2022Comments
-
george koller almost 2 years
Is there a Language supported way make a full (deep) copy of an Object in Dart?
Secondary only; are there multiple ways of doing this, and what are the differences?
Thanks for clarification!
-
george koller over 11 yearsThanks, and I did just end writing a clone method myself for the few classes where I need to make a copy (not just a reference). I was spoiled by Ruby - thought this was a standard language feature.
-
srcspider about 11 yearsit's suppose to be a standard language feature =_="
-
Michał Šrajer over 9 yearseven in official dart polymer tutorial they implement copyCodelab() function by hand. There really suppose to be such stdlib functionality. I'll file a bug for that.
-
Azael about 9 yearsThis might work for a simple <String,String> Map, but it will not for more complex maps like <String,Map>. I had the same idea like you, but it didnt work.
-
Moshe Shaham about 7 years
from
is a constructor. usenew Map.from(mapA);
-
stackunderflow over 5 years@MosheShaham i don't get it
-
stackunderflow over 5 yearshow about 6 years later? is this answer still a truth?
-
Luke Pighetti about 5 years@jerinho you are correct that Moshe Shaham's solution does not work for nested maps.
-
Timmmm about 5 yearsWell this is disappointing. To be fair, many many languages suffer from this issue, even Go has no way to copy an object like you can in C++ or Rust. Anyway here is a recent issue I found for this.
-
Pedro Massango almost 5 yearsHi @Phill I copy/paste your code and it is not working. Can you improve it?
-
Phill Wiggins almost 5 yearsHey @pedromassango. It's difficult to improve that code. Send me your code or implementation and I can show you. Something like:- ```var newObject = Random object.clone(oldObject) will return a copied instance.
-
Pedro Massango almost 5 yearsIt was giving me a error, I just replaced super by this
-
Timmmm almost 5 yearsit loses type information, and it only works for object types that can be represented by JSON. Most importantly it's way slower than it should be.
-
Phill Wiggins almost 5 yearsNot sure why this was downvoted either. It's the closest and cleanest possible way to clone an object without using reflection.
-
user48956 over 4 yearsThis is the wrong answer. Just because a language has pass-by-reference calls, doesn't mean deep copying is not supported.
-
JAR.JAR.beans over 4 years@user48956 Would be great if you can elaborate. The need is a Map of Maps. Say, a complex configuration, The requirement is to be fully clone this, such that it's protected (and maybe even based on need, changed) inside a specific process, but the original object remains unchanged. many languages supports pass-by-ref but also have deep copying out of the box.
-
user48956 over 4 yearsSure language like scala support deep copies by provided methods to reflect the constructor parameter names, types and values (and you can use them to serialize many classes). Language like python provide reflection methods to find an objects class names and attributes (and use them to perform auto-serialization and deep copying). In 2020, these features from 1990 are what we’ve come to expect in a programmable language.
-
JAR.JAR.beans over 4 yearsSorry. Lost you at 1990. deepcopy is a convenient method, syntactic sugar. Any one can implement this (some ways for that, from full serialization and deserialization to recursive looping over the object). The question here is, does Dart has this out of the box, The answer is - No. How can this be a wrong answer? Is there a discussion about "is deep copy a good idea", sure. But I don't think it's related.
-
LMD over 4 yearsCloning using JSON is no good idea. It limits the objects you can clone & reduces performance.
-
dfmiller about 4 yearsSuper lame, give-up-the-ship answer. If nothing else you can loop through each of the objects properties to create a new object.
-
K-Dawg almost 4 yearsthis also doesn't work well if the object has a contains a list of other serializable objects. For example Order has a list of products... even if products are serializable you will see an issue when there's a product in the order.
-
Juliano over 3 yearsThe problem of this solution is when you want to set a null value to variable.
-
maPer77 over 3 yearsReally, a suggestion that I can think of now is to set it to null after copying ...: // --------------------------------------- Item item2 = item1.copyWith( id: 2, nome: 'Pedro de Nobrega', lista: ['4', '5', '6', '7', '8'] ); item2.email = null; // ---------------------------------------
-
Juliano over 3 yearsYeah, but this would not work in a immutable objected, where everything is final. I have a suggestion: Item copyWith({ int Function() id, String Function() name .. }) { return Item( id: id?.call() ?? this.id, nome: nome?.call() ?? this.name, ... ); } Now you can call: item.copyWith(name: () => null);
-
Tuan van Duong over 3 yearsIt works for me when I customise it into
ClassName.fromJson(jsonDecode(jsonEncode(object)));
. Thanks. -
Haroon khan over 3 yearsIn this case, you'll also need to write fromJson() for all the child classes as well which a lot of work to be done.
-
Baig over 3 yearsYes, you can use stackoverflow.com/a/26616081/1556386 solution too if you don't want to implement fromJson()
-
cs guy over 3 yearsseems good but the owner doesnt seem to maintain the repo. I dont suggest using random 3rd party packages like this.
-
LP Square over 3 yearsI personally prefer the copy_with_extension_gen 1.4.0 package, it basically does the same thing but gives you more control and is being maintained
-
Corentin Houdayer almost 3 yearsIt does not work. Here is the exception on my custom model. Class 'Scenario' has no instance getter 'keys'. Receiver: Instance of 'Scenario' Tried calling: keys
-
Pranav Kasetti almost 3 yearsThis behaviour comes automatically with type promotion.
-
Edeson Bizerril over 2 yearsThis is the simplest and most straightforward approach. I tried several measures and they are all too complicated and not worth it.
-
West over 2 yearsThis works thanks. Been struggling all day with a bug due to shallow cloning because I always thought
Map.from
always deep copies and I had been using that. -
stan over 2 yearsGreat solution, since we have already added JSON support for server communication
-
Adrian Moisa over 2 yearsYes, that works great when you already have
fromJson()
in your models -
jamesdlin about 2 yearsThis will copy the
Map
itself, but it will not perform a deep copy of theMap
s keys and values. (Map
keys should be immutable objects, though.) -
adel parsa about 2 yearsyes, unfortunately, I think this is one of the dart language weaknesses. it hasn't a safe way to simple or deep clone, especially for classes
-
jamesdlin about 2 yearsThis is not an answer to the question. As asked, the answer to the question is "There is no general way to create a copy of an arbitrary object in Dart". There can be ways to create copies for specific types of objects, but enumerating those would be an overly broad question.
-
jamesdlin about 2 yearsAdditionally, this is an outdated way to copy
Map
s. Since at least Dart 2, usingMap.from
/Set.from
/List.from
is discouraged since they lose type information. UsingMap.of
/Set.of
/List.of
is better, or forSet
s andList
s,.toSet()/
.toList()`. -
jamesdlin almost 2 yearsAlso, I somehow forgot to mention that this does not create a deep copy of a
Map
. It creates a shallow copy. -
jamesdlin almost 2 years@dfmiller No, you can't. The compiler cannot automatically choose which constructor should be invoked for each member, if a constructor is even available. What would the compiler do if an object has a member with declared with the type of an abstract base class? Or, if you expect that "looping over each of the object's properties" be done at runtime, then that would require runtime reflection, which would penalize performance and code size.
-
Andres Castañeda almost 2 yearsThis works for me when i combine it with equatable to do comparisons