In the next example I am creating several objects/subobjects for an object called structA.
I also create an object called structB and copy subobjects from structA to structB.
The problem I think I am facing is that the dup method does a shallow copy. Ideally I want a full copy of the subobjects of structA. I read I should use the clone method.
create a deep copy (#clone): Constructs a new object with all its properties’ values being recursive deep copies of the original object’s properties. There is no shared state and the new object is a completely independent copy, including everything inside it. This may not be available for every type.
However this gives an error
There was a problem expanding macro 'macro_139949861143760'
Code in /usr/share/crystal/src/array.cr:696:5
696 | {% if T == ::Bool || T == ::Char || T == ::String || T == ::Symbol || T < ::Number::Primitive %}
^
Called macro defined in /usr/share/crystal/src/array.cr:696:5
696 | {% if T == ::Bool || T == ::Char || T == ::String || T == ::Symbol || T < ::Number::Primitive %}
Which expanded to:
> 4 | hash[object_id] = clone.object_id
> 5 | each do |element|
> 6 | clone << element.clone.as(T)
^----
Error: undefined method 'clone' for Node (compile-time type is Node+)
Example code
class Node
property name : String = ""
property nodes : Array(Node)
def initialize(name : String)
@name = name
@nodes = [] of Node
end
def to_s
"address #{self} #{@name}"
end
end
class StructDef < Node
end
class FunctionDef < Node
end
class FunctionCall < Node
end
# A
structA = StructDef.new("A")
# struct B
structB = StructDef.new("B")
functiondef1 = FunctionDef.new("f1")
functiondef2 = FunctionDef.new("f2")
functioncall1 = FunctionCall.new("f1")
functioncall2 = FunctionCall.new("f2")
functiondef1.nodes << functioncall1
functiondef2.nodes << functioncall2
structA.nodes << functiondef1
structA.nodes << functiondef2
#
# dump A
#
puts "struct A #{structA.to_s}"
structA.nodes.each do |n|
puts "\tnode #{n.to_s}"
n.nodes.each do |x|
puts "\t\tsubnode #{x} name #{x.name}"
end
end
puts
puts "copy nodes from A to B"
puts
#
# The addresses of B nodes are the same as the addresses of A nodes
# when using dup. Try the clone method instead
#
structB.nodes = structA.nodes.clone #nodes.dup
#
# dump B
#
puts "struct B #{structB.to_s}"
structB.nodes.each do |n|
puts "\tnode #{n.to_s}"
n.nodes.each do |x|
puts "\t\tsubnodes #{x} name #{x.name}"
end
end
Crystal 1.0.0 [dd40a2442] (2021-03-22)
LLVM: 10.0.0
Default target: x86_64-unknown-linux-gnu