On 23/03/2011, at 6:29 AM, Ariel Feinerman wrote:

> Hi,
> 
> can someone look at and say is a returning of immutable objects necessary or
> no?
> 
> @interface XMLElement : NSObject {
> 
> 
> NSString *_name;
> 
> NSMutableString *_text;
> 
> NSMutableDictionary *_attributes;
> 
> NSMutableArray *_children;
> 
> XMLElement *_parent;
> 
> }
> 
> @implementation XMLElement
[]

> - (NSArray *) children {
> 
> return [[_children copy] autorelease];
> 
> }


No, but neither is performing all this excessive copying.

For example your -children method can simply be:

- (NSArray*) children
{
    return _children;
}


That's because a) NSMutableArray IS a NSArray, and b) your method has told its 
clients it is returning an NSArray, so the client has no right to go any 
further than the methods of NSArray with that object, that is, it cannot make 
use of knowledge it doesn't have to treat it as mutable. If you want the client 
to know that the array really is mutable, your return type should say so.

The only issue is whether having returned the array, its contents could mutate 
while someone else is retaining it. But if the client is holding onto it that 
long (in a synchronous situation) its contents won't reflect the reality of the 
content of the object it got it from in any case. Alternatively, once the tree 
is built from the XML document, why would the structure change? If you're 
writing an editor, the structure will change, but in that case you probably 
won't have a case where a stale copy of 'children' is cached anywhere. In all 
the typical cases, the copy is likely redundant. If a client knows that it will 
be holding on to the array for "a long time", and that it got it from an object 
whose contents are probably dynamic (according to this very common pattern) 
then it can make a copy itself if it needs to. It is in a better position than 
the vending object to know whether the copy is needed or not (which is why most 
copying that is done is implemented by an object setter, not in a getter).

On the other hand whether to copy or not is really a (usually minor) 
performance issue rather than anything more fundamental, so worrying about it 
now is unlikely to be worthwhile. However I think that paranoia leading to 
copying everything everywhere indicates a basic lack of understanding about the 
design you're implementing. By habit and reflex,  not copying is the norm, and 
copying should only be done when it is understood that it is truly necessary. 
Doing it "just in case" is pointless.

By the way if you're building an XML tree (presumably from running NSXMLParser) 
perhaps the NSXMLNode family of objects would be a better choice. If you are 
writing a streaming parser where the elements are short-lived, I wouldn't 
expect the element lifetimes to be very long - there are unlikely to be clients 
that will hold your 'children' array beyond the existence of those children. I 
just wrote an XML parser like this myself - each parent element maintains a 
stack of children which are pushed and popped as each child element comes into 
being, gets processed and then is finished with. Thus the 'children' array 
(really a stack) is quite dynamic, and usually rather short. The only object 
that really cares about that stack is the object holding it, so while I do have 
a method for returning that array, it doesn't perform a copy, and that hasn't 
caused any problems (in fact, I couldn't swear it's  ever used, but it's a 
habit to provide accessors for private container ivars in the base class for 
the implementing object - you never know when someone will want it).

To harp on this point about copying:

> - (NSArray *) elementsForName: (NSString *) name {
> 
> NSMutableArray *children = [NSMutableArray new];
> 
> for (XMLElement *element in _children)
> 
> if ([[element name] isEqualToString: name])
> 
> [children addObject: element];
> 
> NSArray *lchildren = [children copy];
> 
> [children release];
> 
> return [lchildren autorelease];
> 
> }

Why do you build an array in perfect isolation, then copy it before returning 
it? The array you just built is not used anywhere else and as soon as it's 
copied it is released and deallocated. The copy is just a waste of time - you 
are perfectly within your contract with your clients to simply return the 
mutable array.

--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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

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

Reply via email to