Re: faster deep copies?

2013-02-14 Thread Uli Kusterer
I wrote a -deepCopy method as part of a protocol on the common collection 
classes. It does a respondsToSelector: and calls -copy if it doesn't. So as 
long as my collection views cover all collection classes to create a new 
NSArray etc. containing copies of the same objects, it mostly works. Downsides: 
This will make immutable copies of mutable objects (if you called -mutableCopy 
where available, you might do the reverse), and you need to be careful that you 
don't miss adding -deepCopy to a class.

Cheers,
-- Uli Kusterer
The Witnesses of TeachText are everywhere...
http://www.zathras.de

On Feb 14, 2013, at 3:07 AM, James Maxwell jbmaxw...@rubato-music.com wrote:

 I've run into a situation where I really need a deep copy of an object. I've 
 implemented this using Apple's recommended approach with 
 NSKeyedArchiver/Unarchiver, and it's nice, simple, and functional. But it's 
 also pretty darn slow -- as in a clear, subjectively apparent performance hit.
 Has anybody had to find a way around this, and if so, what did you do? Or if 
 anybody just has a nice, creative thought about another way of doing it, I'd 
 love to hear about it.
 
 The object(s) being copied are custom classes, and there's a chance I may be 
 able to get away with copying only certain properties (i.e., rather than 
 archiving the entire graph from the root object), so I'll look into making a 
 deepCopy method that's more selective. But I'd appreciate any thoughts in 
 the meantime.
 
 Thanks in advance.
 
 J.
 ___
 
 Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
 
 Please do not post admin requests or moderator comments to the list.
 Contact the moderators at cocoa-dev-admins(at)lists.apple.com
 
 Help/Unsubscribe/Update your Subscription:
 https://lists.apple.com/mailman/options/cocoa-dev/witness.of.teachtext%40gmx.net
 
 This email sent to witness.of.teacht...@gmx.net


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: faster deep copies?

2013-02-14 Thread Uli Kusterer
What NSKeyedArchiver probably does is have a dictionary that maps the original 
object pointer values to the copied objects. So instead of just straight-out 
copying an object, it does:

NSString* theKey = [NSString stringWithFormat: @%p, theOriginal];
id theCopy = [objectCopies objectForKey: theKey];
if( !theCopy )
{
theCopy = [theOriginal copy];
[objectCopies setObject: theCopy forKey: theKey];
}

That way, every object only gets copied once, and the copy re-used in other 
spots. That may be part of why it is slower. (NB - you could probably use an 
NSValue +valueWithUnretainedPointer: or whatever as the key, I just quickly 
typed this untested code into the e-mail)

Cheers,
-- Uli Kusterer
The Witnesses of TeachText are everywhere...
http://www.zathras.de

On Feb 14, 2013, at 3:57 AM, Ken Thomases k...@codeweavers.com wrote:
 Your question prompted me to try to design an analog of NSKeyedArchiver, 
 NSCode, and NSCoding that would generate the new object graph on the fly as 
 it went instead of producing a data object.  The idea is that the copier (the 
 analog of the archiver/coder) would know which objects had already been 
 copied and so would avoid over-duplicating them in the new graph.  However, 
 that ends up being hard because each object has to copy its related object 
 before it's complete enough to be registered with the copier.  So, it isn't 
 successful in avoiding the potential for infinite recursion.


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: faster deep copies?

2013-02-14 Thread Tom Davie

On 14 Feb 2013, at 02:07, James Maxwell jbmaxw...@rubato-music.com wrote:

 I've run into a situation where I really need a deep copy of an object. I've 
 implemented this using Apple's recommended approach with 
 NSKeyedArchiver/Unarchiver, and it's nice, simple, and functional. But it's 
 also pretty darn slow -- as in a clear, subjectively apparent performance hit.
 Has anybody had to find a way around this, and if so, what did you do? Or if 
 anybody just has a nice, creative thought about another way of doing it, I'd 
 love to hear about it.
 
 The object(s) being copied are custom classes, and there's a chance I may be 
 able to get away with copying only certain properties (i.e., rather than 
 archiving the entire graph from the root object), so I'll look into making a 
 deepCopy method that's more selective. But I'd appreciate any thoughts in 
 the meantime.

One possible approach to this (though not one that's going to be as fast as a 
custom deepCopy method), would be to implement your own NSCoder subclass.  I 
have in the past made keyed archivers which are substantially quicker than 
apple's, and encode into substantially smaller byte formats.

Thanks

Tom Davie
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: faster deep copies?

2013-02-14 Thread Ken Thomases
On Feb 14, 2013, at 8:30 AM, Uli Kusterer wrote:

 On Feb 14, 2013, at 3:57 AM, Ken Thomases k...@codeweavers.com wrote:
 Your question prompted me to try to design an analog of NSKeyedArchiver, 
 NSCode, and NSCoding that would generate the new object graph on the fly as 
 it went instead of producing a data object.  The idea is that the copier 
 (the analog of the archiver/coder) would know which objects had already been 
 copied and so would avoid over-duplicating them in the new graph.  However, 
 that ends up being hard because each object has to copy its related object 
 before it's complete enough to be registered with the copier.  So, it isn't 
 successful in avoiding the potential for infinite recursion.
 
 What NSKeyedArchiver probably does is have a dictionary that maps the 
 original object pointer values to the copied objects. So instead of just 
 straight-out copying an object, it does:
 
 NSString* theKey = [NSString stringWithFormat: @%p, theOriginal];
 id theCopy = [objectCopies objectForKey: theKey];
 if( !theCopy )
 {
   theCopy = [theOriginal copy];
   [objectCopies setObject: theCopy forKey: theKey];
 }
 
 That way, every object only gets copied once, and the copy re-used in other 
 spots. That may be part of why it is slower. (NB - you could probably use an 
 NSValue +valueWithUnretainedPointer: or whatever as the key, I just quickly 
 typed this untested code into the e-mail)

That's what I considered but it doesn't work.  You can't add the copy into the 
archiver's database of already-copied objects until it's complete.  But, for 
the case where the graph has cycles, making the complete copy will try to make 
copies of all its related objects first.  When the cycle loops back to the same 
original, that original still does not have a copy in the database, so it tries 
to make another copy.  Infinite recursion.

Regards,
Ken


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: faster deep copies?

2013-02-14 Thread Jerry Krinock
I've taken the plunge and written a mutable deep copy method for NSObject in my 
applications.

So far, I've used it only to add interesting arbitrary objects to NSError 
userInfo dictionaries.  Unliike Ken and Uli, I'd never thought about the 
circular references in object trees, but I ran into a different problem, which 
you should also watch out for, which is that descendant objects are not 
necessarily serializable, encodeable, or respond to -mutableCopy.

https://github.com/jerrykrinock/CategoriesObjC/blob/master/NSObject%2BDeepCopy.h

My next commit of that will have at least some warnings about circular 
references in object trees :)


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: faster deep copies?

2013-02-14 Thread Graham Cox

On 14/02/2013, at 1:07 PM, James Maxwell jbmaxw...@rubato-music.com wrote:

 I've run into a situation where I really need a deep copy of an object.



My question would be: are you really sure?

Yes, there are times you need a deep copy, but surprisingly few. Often you can 
redesign your code not to need one

--Graham


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: faster deep copies?

2013-02-14 Thread Gerriet M. Denkmann

On 15 Feb 2013, at 01:25, Ken Thomases k...@codeweavers.com wrote:

  
 
 On Feb 14, 2013, at 8:30 AM, Uli Kusterer wrote:
 
 On Feb 14, 2013, at 3:57 AM, Ken Thomases k...@codeweavers.com wrote:
 Your question prompted me to try to design an analog of NSKeyedArchiver, 
 NSCode, and NSCoding that would generate the new object graph on the fly as 
 it went instead of producing a data object.  The idea is that the copier 
 (the analog of the archiver/coder) would know which objects had already 
 been copied and so would avoid over-duplicating them in the new graph.  
 However, that ends up being hard because each object has to copy its 
 related object before it's complete enough to be registered with the 
 copier.  So, it isn't successful in avoiding the potential for infinite 
 recursion.
 
 What NSKeyedArchiver probably does is have a dictionary that maps the 
 original object pointer values to the copied objects. So instead of just 
 straight-out copying an object, it does:
 
 NSString* theKey = [NSString stringWithFormat: @%p, theOriginal];
 id theCopy = [objectCopies objectForKey: theKey];
 if( !theCopy )
 {
  theCopy = [theOriginal copy];
  [objectCopies setObject: theCopy forKey: theKey];
 }
 
 That way, every object only gets copied once, and the copy re-used in other 
 spots. That may be part of why it is slower. (NB - you could probably use an 
 NSValue +valueWithUnretainedPointer: or whatever as the key, I just quickly 
 typed this untested code into the e-mail)
 
 That's what I considered but it doesn't work.  You can't add the copy into 
 the archiver's database of already-copied objects until it's complete.  But, 
 for the case where the graph has cycles, making the complete copy will try to 
 make copies of all its related objects first. When the cycle loops back to 
 the same original, that original still does not have a copy in the database, 
 so it tries to make another copy.  Infinite recursion.

Why not keep a mutable dictionary M and on encountering an object (in the 
scanning phase) do:

if object not in mutable dictionary M then
add to M: key = address of object, value = NSNull
continue walking the object tree
else
do nothing
endif

And in the second (copy) phase do:

if value of object = NSNull then copy it and set the value in M to the copied 
object
else just store a link to the already copied object.

Should work with cycles. Might not be faster than NSArchive.

Kind regards,

Gerriet.



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: faster deep copies?

2013-02-14 Thread James Maxwell
Well, yes, that's a good question. 
But I spent a good deal of time trying to find a way around it and couldn't. 
However, in the meantime I discovered that by using a home-spun -deepCopy 
method on just a couple of classes I was able to solve my mutation problem, 
without resorting to the wholesale NSKeyedArchiver approach of grabbing the 
entire object graph.
So, problem solved. If I ever feel inclined to discover a deeper fix I will, 
but it won't be any time soon!

J.

On 2013-02-14, at 4:01 PM, Graham Cox graham@bigpond.com wrote:

 
 On 14/02/2013, at 1:07 PM, James Maxwell jbmaxw...@rubato-music.com wrote:
 
 I've run into a situation where I really need a deep copy of an object.
 
 
 
 My question would be: are you really sure?
 
 Yes, there are times you need a deep copy, but surprisingly few. Often you 
 can redesign your code not to need one
 
 --Graham
 
 

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


faster deep copies?

2013-02-13 Thread James Maxwell
I've run into a situation where I really need a deep copy of an object. I've 
implemented this using Apple's recommended approach with 
NSKeyedArchiver/Unarchiver, and it's nice, simple, and functional. But it's 
also pretty darn slow -- as in a clear, subjectively apparent performance hit.
Has anybody had to find a way around this, and if so, what did you do? Or if 
anybody just has a nice, creative thought about another way of doing it, I'd 
love to hear about it.
 
The object(s) being copied are custom classes, and there's a chance I may be 
able to get away with copying only certain properties (i.e., rather than 
archiving the entire graph from the root object), so I'll look into making a 
deepCopy method that's more selective. But I'd appreciate any thoughts in the 
meantime.

Thanks in advance.

J.
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: faster deep copies?

2013-02-13 Thread Ken Thomases
On Feb 13, 2013, at 8:07 PM, James Maxwell wrote:

 I've run into a situation where I really need a deep copy of an object. I've 
 implemented this using Apple's recommended approach with 
 NSKeyedArchiver/Unarchiver, and it's nice, simple, and functional. But it's 
 also pretty darn slow -- as in a clear, subjectively apparent performance hit.
 Has anybody had to find a way around this, and if so, what did you do? Or if 
 anybody just has a nice, creative thought about another way of doing it, I'd 
 love to hear about it.
 
 The object(s) being copied are custom classes, and there's a chance I may be 
 able to get away with copying only certain properties (i.e., rather than 
 archiving the entire graph from the root object), so I'll look into making a 
 deepCopy method that's more selective. But I'd appreciate any thoughts in 
 the meantime.

I'd expect a -deepCopy method to be substantially faster even if it weren't any 
more selective about which properties get copied.  The main difficulty is when 
your object graph may have cycles or diamonds.  Archiving will store each 
object exactly once and all references to it will refer to that; then, on 
unarchiving, the references will be restored properly.  A naive deep copy will 
cause an object which is referenced from two points in the object graph to end 
up as two separate objects in the new graph.  And cycles can cause infinite 
recursion.

Your question prompted me to try to design an analog of NSKeyedArchiver, 
NSCode, and NSCoding that would generate the new object graph on the fly as it 
went instead of producing a data object.  The idea is that the copier (the 
analog of the archiver/coder) would know which objects had already been copied 
and so would avoid over-duplicating them in the new graph.  However, that ends 
up being hard because each object has to copy its related object before it's 
complete enough to be registered with the copier.  So, it isn't successful in 
avoiding the potential for infinite recursion.

An obvious question is: have you analyzed the NSKeyedArchiver approach to 
understand why it's slow?

Regards,
Ken


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com