Proper way to implement clone() (when inheritance and deep copy are involved)

319 views
Skip to first unread message

azrafe7

unread,
Mar 18, 2016, 12:37:41 PM3/18/16
to Haxe
Hi list, this one got me thinking for the last week, and still I can't find a suitable solution for it.
After a bunch of (failed) experiments I'm hoping to find some help here...

The problem goes like this:

 1. I have a tree of Nodes
 2. each node can have a list of children (no cycles!, and there's a root)
 3. a Node has subclasses (in my case Element extends Node, and Document extends Element)
 4. the children array can contain nodes of any of these subclasses
 5. Node and subclasses use different parameters in the respective constructors (this could be changed, but might be worthy pointing it out)
 6. I want to be able to call clone() on any type of Node (so also a subclass of it) and get back a deep copy of it (BUT with each node cloned of the correct type) 

A very simplified example/stub of what I'd like to achieve (take it as pseudo-code) is here: http://try.haxe.org/#3B6A6

Don't know if it's worth mentioning, but this is related to translating clone() functionality from java.

I've tried many things hoping to solve this (generics, static copy(), extensions, etc. ), but just can't wrap my head around it.
(f.e.: I've tried using a cloneInto(T), but that could not be extended, as the superclass would have a different signature)

I realize the exposition of my problem so far might be lacking. Please ask me anything so I can clarify.
And since I'm sure I must be doing something wrong in my attempts (which are all messily scattered in my HD), any help is more than welcome!

Mark Knol

unread,
Mar 18, 2016, 1:02:51 PM3/18/16
to Haxe
The dumbest but easiest thing you can do is Serializer and Unserializer an object:

Mark Knol

unread,
Mar 18, 2016, 1:04:10 PM3/18/16
to Haxe
If the values you are serializing can contain circular references or objects repetitions, you should set Serializer.USE_CACHE to true to prevent infinite loops.

azrafe7

unread,
Mar 18, 2016, 4:43:31 PM3/18/16
to Haxe
Thanks Mark... Unfortunately it won't work in my specific case, as there are private fields that need to be cloned (and I'd also like to avoid reflection for performance reasons).

azrafe7

unread,
Mar 18, 2016, 5:03:24 PM3/18/16
to Haxe
After trying your tryhaxe code I see that private vars don't seem to pose a problem, but in my case I also have fields that don't need cloning (they're computed from other props). Plus I'd like to have a clone() I can call on Element (or Document) that deep_copies all children too. 

Honestly I realize I should update the example to better show what my aim is (I'll do that), but it would get pretty big/messy. I suppose co/contravariance come into play here, but really can't think of a proper/somewhat-simple way to solve it. (I'm finding quite difficult to explain my problem in plain words, sorry)



On Friday, March 18, 2016 at 5:37:41 PM UTC+1, azrafe7 wrote:

Ashiq A.

unread,
Mar 18, 2016, 5:05:08 PM3/18/16
to haxe...@googlegroups.com
Maybe you can upload some code to GitHub to facilitate discussion and/or caveats.

I think serializing is (generally) the best way to handle deep copying. Maybe in your case, this is "good enough"?

--
To post to this group haxe...@googlegroups.com
http://groups.google.com/group/haxelang?hl=en
---
You received this message because you are subscribed to the Google Groups "Haxe" group.
For more options, visit https://groups.google.com/d/optout.

Marcelo de Moraes Serpa

unread,
Mar 18, 2016, 5:33:26 PM3/18/16
to haxe...@googlegroups.com
@Ashiq Agreed -- please put a gist up with an example of the data structure you're trying to clone, it'll be much easier.

azrafe7

unread,
Mar 18, 2016, 5:52:48 PM3/18/16
to Haxe
Gist it is! ;)

I agree with you, it'll make things much more useful for discussion, and easier for you to lend help. 

I'm trying to reduce my use case right now (will take a bit throwing out unnecessary things). I'll post a gist or two by tomorrow (both haxe and java), so I can give a meaningful example or what I'm trying to achieve. Thanks in advance.


On Friday, March 18, 2016 at 5:37:41 PM UTC+1, azrafe7 wrote:

Yoni Gueta

unread,
Mar 18, 2016, 5:59:49 PM3/18/16
to Haxe

hi

i think the weird part comes from creating an instance of Node inside the Element clone method.
im a little confused on how the generics handle this situation, but side stepping the issue altogether,  implement a copy method to handle the data transfer, while the clone method just creates the proper instance

azrafe7

unread,
Mar 18, 2016, 6:32:35 PM3/18/16
to Haxe
@Yoni, you are closer to what I'm trying to achieve, and I must admit that my latest approach is very similar to yours (a separated method to handle the copy working as a cloneInto(T)), although I was trying to implement it as a parameterized static function (something like copy<T>(from:T, into:T, copier:T->T->Void)). But still didn't work.
(One problem being that it's not possible to override a function with different params)

The drawback comes in when you try to account for a children of Nodes (which can contain any sublclass of Node) and still want to deep clone the root (in the sense that any node in that array has to be clone as its class, so if it's an Element, it has to be cloned as that).

This response might be really incomprehensible, I know and I'm sorry for it, but I feel there's too much going on and really can't find the words to explain it better (and hell, I can't understand all the implications). Hope my future gist/s will clarify something.


On Friday, March 18, 2016 at 5:37:41 PM UTC+1, azrafe7 wrote:

Yoni Gueta

unread,
Mar 18, 2016, 8:10:56 PM3/18/16
to Haxe
 
well i'm probably oversimplifying the matter
but isnt this enough?

anyway, good luck :)

Víctor R. Escobar

unread,
Mar 19, 2016, 2:24:51 PM3/19/16
to Haxe
Hi Azrafe7,

Why don't you use Reflect.copy? It is way much faster than reserialize and perfect for little fast copies when performance is not relevant: http://try.haxe.org/#47fe3

For a better overkill (more over engineered solution), why don't you use a persistent data structure such as clojure trees? All them share the same memory and each operation returns a new tree, in that way nothing can modify your object but create a new instance at cost(1). I am not aware of any pure haxe implementation of them, so you may have to interface a library for your target or port them.

I would like to see the second solution native to haxe in some point, I wish I'd have time to port them.

Have a nice day.

azrafe7

unread,
Mar 19, 2016, 4:20:59 PM3/19/16
to Haxe
@Yoni, your last post seems very likely to be what I need, thanks! That ICopy interface was the missing piece ( silly me for not thinking of it ;) ).

It will need some very minor changes to fit my use case, but it seems to be it. Gonna try to integrate it now and report back.

Thanks all for your support.

(for completeness, here's a reduced java example of what I was trying to accomplish: https://gist.github.com/azrafe7/97fe76908f867ae24bdd)


On Friday, March 18, 2016 at 5:37:41 PM UTC+1, azrafe7 wrote:
Reply all
Reply to author
Forward
0 new messages