On Feb 9, 2011, at 12:46, Greg Parker wrote:

> Initializing the error to nil is helpful to protect against one nasty hole in 
> the pattern. Consider this code:
> 
>     NSError *error;
>     id result = [receiver doSomethingWithError:&error];
>     if (!result) NSLog(@"error %@", error);
> 
> On failure, -doSomethingWithError: returns nil and sets error. But if 
> receiver is nil, -doSomethingWithError: returns nil and does not set error. 
> In that case, the error-handling code may crash after using the uninitialized 
> error value. If you set error=nil in advance, you can do something correct 
> when receiver is nil.

After reading this, I was going to break my resolution to stay out of the 
thread, to say, "OK, Greg Parker wins with an unanswerable argument." Except 
that after a little thought I decided it wasn't unanswerable. :)

The problem with your initialization pattern**:

>     NSError *error = nil;
>     id result = [receiver doSomethingWithError:&error];
>     if (!result) NSLog(@"error %@", error);


as a defensive technique is that it breaks down in the following variant of the 
scenario:

>     NSError *error = nil;
>     id result = [receiver1 doSomethingWithError:&error];
>     if (!result) NSLog(@"error %@", error);

>    result = [receiver2 doSomethingWithError:&error];
>     if (!result) NSLog(@"error %@", error);


Now, I'll be the first to admit that my second example is bait-and-switch. We 
weren't talking about multiple method invocations, but in this particular 
scenario the second invocation could result in mis-reporting an error actually 
detected earlier.

What's *really* going on here is a different problem -- it's related to the 
validity of return values from messages to a nil receiver, a topic you've 
weighed in on the past. Just as a struct return value from a message to a nil 
object isn't valid, an error "return" value from a message to a nil object 
isn't valid either.

Therefore, I'd suggest, the morally correct version of my second example is not 
this:

>     NSError *error;
>     error = nil;
>     id result = [receiver1 doSomethingWithError:&error];
>     if (!result) NSLog(@"error %@", error);
>     error = nil;

>     result = [receiver2 doSomethingWithError:&error];
>     if (!result) NSLog(@"error %@", error);


but this:

>     NSError *error;
>     id result = [receiver1 doSomethingWithError:&error];
>     if (receiver1 && !result) NSLog(@"error %@", error);

>    result = [receiver2 doSomethingWithError:&error];
>     if (receiver2 && !result) NSLog(@"error %@", error);


which is closer to what you'd have to do if 'result' was a NSPoint, say, 
instead of an id -- and is clearer about what subtlety is being dealt with.

So unless you have another unanswerable argument up your sleeve, I'll stick 
with my earlier claim that setting error to nil actively leads the unwary 
developer astray to some degree.


** Actually, there might be a problem even with the simple version of your 
initialization pattern: there might still need to be additional code later to 
deal with the nil error object after the error-handling code path was taken. 
Probably, in most cases, there won't be a transparent way of handling the nil 
receiver.

_______________________________________________

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