You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The documentation for the Dictionary class states "If deep is true, inner Dictionary and Array keys and values are also copied, recursively." for the duplicate method. However, the objects in dictionaries created via the Dictionary.duplicate(true) function still act as references to those in the duplicated dictionary, implying either that a shallow copy or a non-recursive deep copy was made, instead of the recursive deep copy proscribed by the documentation.
Steps to reproduce
Create a dictionary. Put an array of objects passed by reference into the dictionary. Call duplicate(true) on the dictionary. Alter an object in the array in the result of the duplicate function. Print or otherwise display the object it corresponds to in the original dictionary. It will appear as if a shallow copy had been made, despite described behavior specifying a deep copy.
Minimal reproduction project (MRP)
I do not currently have access to a Godot editor to make a MRP. I hope the issue is simple enough fort my description to be sufficient.
The text was updated successfully, but these errors were encountered:
Duplicating objects is tricky because it's not always obvious whether it's needed or not. Resources can often be considered shared. Nodes can have children and connections. Objects other than Nodes and Resources don't even have a built-in duplicate() method. Object properties are divided into those exported with PROPERTY_USAGE_STORAGE and those not essential for serialization/duplication.
Try the following function as a workaround:
Code
staticfuncrecursive_duplicate(value: Variant, recursion_count: int=0) ->Variant:
constMAX_RECURSION: int=100ifvalueisArray:
vararray: Array=valuevarcopy: Array=Array(
[],
array.get_typed_builtin(),
array.get_typed_class_name(),
array.get_typed_script(),
)
ifrecursion_count>MAX_RECURSION:
push_error("Max recursion reached.")
returncopyrecursion_count+=1forelement: Variantinarray:
copy.append(recursive_duplicate(element, recursion_count))
returncopyifvalueisDictionary:
vardictionary: Dictionary=valuevarcopy: Dictionary= {}
ifrecursion_count>MAX_RECURSION:
push_error("Max recursion reached.")
returncopyrecursion_count+=1forkey: Variantindictionary:
copy[recursive_duplicate(key, recursion_count)] \
=recursive_duplicate(dictionary[key], recursion_count)
returncopyifvalueisObject:
ifrecursion_count>MAX_RECURSION:
push_error("Max recursion reached.")
returnnullrecursion_count+=1varobject: Object=valueifnotis_instance_valid(object):
returnnull# TODO `return object`?varobject_class: StringName=object.get_class()
ifnotClassDB.can_instantiate(object_class):
push_error('Cannot instantiate "%s".'%object_class)
returnnullvarcopy: Object=ClassDB.instantiate(object_class)
forproperty: Dictionaryinobject.get_property_list():
varproperty_name: String=property.namevarproperty_usage: int=property.usage# TODO: Check `PROPERTY_USAGE_ALWAYS_DUPLICATE`?ifnot (property_usage&PROPERTY_USAGE_STORAGE):
continueifproperty_usage&PROPERTY_USAGE_NEVER_DUPLICATE:
copy.set(property_name, object.get(property_name))
else:
copy.set(
property_name,
recursive_duplicate(object.get(property_name), recursion_count),
)
returncopy# `Packed*Array`s are pass-by-reference types, but they cannot contain# pass-by-reference elements, so we can use the standard method.iftypeof(value) >=TYPE_PACKED_BYTE_ARRAY:
@warning_ignore("unsafe_method_access")
returnvalue.duplicate()
# A pass-by-value type.returnvalue
Tested versions
Personal experience: 4.3
I have also seen documentation of this bug from over 4 years ago, as well as some more recent reports.
System information
Windows 11
Issue description
The documentation for the Dictionary class states "If deep is true, inner Dictionary and Array keys and values are also copied, recursively." for the duplicate method. However, the objects in dictionaries created via the Dictionary.duplicate(true) function still act as references to those in the duplicated dictionary, implying either that a shallow copy or a non-recursive deep copy was made, instead of the recursive deep copy proscribed by the documentation.
Steps to reproduce
Create a dictionary. Put an array of objects passed by reference into the dictionary. Call duplicate(true) on the dictionary. Alter an object in the array in the result of the duplicate function. Print or otherwise display the object it corresponds to in the original dictionary. It will appear as if a shallow copy had been made, despite described behavior specifying a deep copy.
Minimal reproduction project (MRP)
I do not currently have access to a Godot editor to make a MRP. I hope the issue is simple enough fort my description to be sufficient.
The text was updated successfully, but these errors were encountered: