On Jul 16, 2009, at 16:49, Timothy Wood wrote:

 So, as an example, I might want do do something like:

- (BOOL)saveSomething:(NSError **)outError;
{
        NSData *data = build some data;

        if ([data writeToFile:path options:someOptions error:outError])
                return YES;

OBError(outError, ErrorCodeEnum, @"some reason", ... other user info k/v pairs ...);
        return NO;
}

 ...

- (BOOL)saveSomething:(NSError **)outError;
{
        NSData *data = build some data;

        // strawman, remember, I'd not do it this way… =)
        [defaults setObject:data forKey:someKey];
        if ([defaults synchronize])
                return YES;

OBError(outError, ErrorCode, @"some reason", ... other user info k/ v pairs ...);
        return NO;
}

Well, now I'm screwed due to these NSError rules. I'm reading *outError for an optional chained NSUnderlyingError and it might be trash.

Sure, I should remember to ignore it or initialize it to nil myself or have a OBBaseError macro, but one day I'll forget. The current rules make me write more and more fragile code than I'd need to if we could just all depend on setting NSError locals to nil before passing them down. I know we can't right now, but I'm saying that makes life harder than it could be. Cocoa is supposed to round off the rough corners in programming! =)

Well, it's a valid but terribly weak argument, if you don't mind my suggesting so.

In the second case, you're not screwed because of "these NSError rules" but because you're using an output parameter of the method as an input parameter to the macro. It's a plain bug, unless you assert it not to be a bug (which is basically what you're doing, which is why I'm calling it "weak").

But your example is weak for another reason. If the methods were this simple, you'd be unlikely to leave outError uninitialized in the second method. It's only going be be an issue in a longer method that does a series of things that can fail, and then you're more likely to write:

        if (![... do something ... error: outError]) {
                OBError (outError, ...);
                return NO;
        }

        if (![... do something else ... error: outError]) {
                OBError (outError, ...);
                return NO;
        }

        ...

and if there's something to do that doesn't return a NSError:

        if (![... do something ...]) {
                OBError (nil, ...);
                return NO;
        }

What's so fragile about that? If you paste it somewhere else, the 'nil' goes with it. :) Is the return-YES-on-success pattern really reasonable for most non-trivial methods?

I should confess my bias here. I'm a big fan of Wil Shipley's "mainline" code approach:

        http://www.wilshipley.com/blog/2005/07/code-insults-mark-i.html

but you have to scroll down a bit to find it:

What you should really do is write "if" statements that check for improperconditions, and if you find them, bail. This cleans your code immensely, in two important ways: (a) the main, normal execution path is all at the top level, so if the programmer is just trying to get a feel for the routine, all she needs to read is the top level statements, instead of trying to trace through indention levels figuring out what the "normal" case is, and (b) it puts the "bail" code right next to the correctness check, which is good because the "bail" code is usually very short and belongs with the correctness check.

(But ignore the part further down where he goes right off the rails about self = [super init]. :) )


_______________________________________________

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