Double braces for start/end blocks

My friend Demitri showed me a coding technique he uses when he has a bunch of lines that need to be preceded by a "start" statement of some sort and followed by an "end" statement of some sort.

A recent example in my own code looks roughly like this:

[self startOutput];  // top-level "start"
 
[self startImageAssets];
[self addImageAssets];
[self endImageAssets];
 
[self startThumbnailAssets];
[self addThumbnailAssets];
[self endThumbnailAssets];
 
[self startAudioAssets];
[self addAudioAssets];
[self endAudioAssets];
 
[self endOutput];  // top-level "end"

The problem is that the "start" and the "end" may be far enough apart that it's not visually apparent that the lines in between are logically nested. In some cases, though not so much in this example, it can be easy to forget to add the "end" statement.

One approach would be to wrap all the interior stuff into a method, so it collapses into one line:

[self startOutput];
[self outputAllAssets];
[self endOutput];

This follows the excellent principle of Keeping Methods Short, and now the beginning/middle/end sequence is clear. But this isn't always convenient, and I don't always prefer it over inlining the intermediate statements.

I've seen code that indents the internal statements like this:

[self startOutput];
 
    [self startImageAssets];
    [self addImageAssets];
    [self endImageAssets];
 
    [self startThumbnailAssets];
    [self addThumbnailAssets];
    [self endThumbnailAssets];
 
    [self startAudioAssets];
    [self addAudioAssets];
    [self endAudioAssets];
 
[self endOutput];

I didn't indent the "add" statements because each of those groups of three lines is short enough that it's obvious what's going on, and I think indenting the middle lines would make the code harder to read, at least to my eye.

The problem with this approach is that when you tell Xcode to Re-Indent, you will lose all your custom indentation. (Side note: I'm not sure, but it seems to me "Re-Indent" in the Xcode menu should be "Re-indent".)

Demitri's solution is to put the internal statements into a C block, like this:

[self startOutput];
{
    [self startImageAssets];
    [self addImageAssets];
    [self endImageAssets];
 
    [self startThumbnailAssets];
    [self addThumbnailAssets];
    [self endThumbnailAssets];
 
    [self startAudioAssets];
    [self addAudioAssets];
    [self endAudioAssets];
}
[self endOutput];

This works nicely, but one teeny-weeny thing about it bothers me. When I see that opening brace it feels like I'm missing a line, like maybe I accidentally deleted an "if" or a "while". I could probably get used to this, especially since the "start" in the line above is a strong clue. But just to help myself see my intentions, I've taken to using double curly-braces:

[self startOutput];
{{
    [self startImageAssets];
    [self addImageAssets];
    [self endImageAssets];
 
    [self startThumbnailAssets];
    [self addThumbnailAssets];
    [self endThumbnailAssets];
 
    [self startAudioAssets];
    [self addAudioAssets];
    [self endAudioAssets];
}}
[self endOutput];

Now when I scan the code I can clearly see that the reason for the block was to indicate logical nesting.

This technique can also be useful for Create/Release pairs in CF code, or alloc/release pairs in Cocoa or iOS code. Or for those times when you create your own autorelease pool:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
{{
    // Autoreleased objects here go into the local pool.
}}
[pool drain];  // Less likely you'll forget to drain the pool.

I believe the example Demitri showed me was a begin/commit animation block in his iOS code. With the double braces it would look like this:

[UIView beginAnimations:animationID context:context];
{{
    // Add an animation to the animation block.
    // Add an animation to the animation block.
    // ...
}}
[UIView commitAnimations];

One concern is that someone else reading my code might be confused if they're not familiar with the convention I adopted. Ideally it would turn out I wasn't the first to think of the double-braces approach, and actually lots of people do it this way. But I haven't come across it. Maybe most people take the first approach I mentioned and create a separate method or function.

I think of the double braces sort of like the double parens in "old-style" init methods (which are not how Apple does them any more, but perfectly fine technically):

if ((self = [super init]))
{
    // ...
}

The double parens avoid a warning from the compiler that you might have meant == instead of =. My double braces avoid a "mental compiler warning" that I might be missing an "if" or a "while".

Crazy me

Learned something this morning from Wikipedia:

A truncated version of the "Crazy Ones" text has been reused in Mac OS X Leopard on the high-resolution icon for TextEdit.

Sure enough, here's the icon:

TextEdit icon

I came across this in a roundabout way. In comments on my earlier post about YoruFukurou (the desktop Twitter client I use), someone asked if it provides a way to find and follow people. I tested by searching for the name "Mike Morton", which turned up mentions of Mike's blog posts about WWDC. On Day 1 he writes:

Everyone got a nice "WWDC 11" sweatshirt. I’m giving mine to my friend Andy, who’s crazy enough that he flew all the way from New York to San Francisco despite having no ticket for the conference. (Andy was not crazy enough to wake up and join us for hours in line, though.)

I'm the crazy Andy. I wanted to reply with something about "Here's to the crazy ones…" and wanted to get the quote right. Hence the Wikipedia discovery.

Thanks, Mike, for the great sweatshirt!

MS online store saves password in clear text

I just bought Office for Mac from microsoft.com. To do so, I created an account. A bit later I realized I'd forgotten my password, so I clicked the necessary links to have it sent to me.

I expected to get either a random temporary password or a one-shot URL I could use to reset my password. Either of these approaches is standard practice. Instead I got an email containing my original password, which means Microsoft is remembering it in clear text.

To see how much more they're remembering I started a new purchase. I saw they had saved my credit card info and billing address. I don't know if the purchase would have gone through if I'd chosen to continue. For all I know they would have prompted me for my password before completing the transaction. Still, that password was exposed to employees of Microsoft and to anyone who hacks into their systems.

I would hope Microsoft does not save full credit card numbers. That would be monumentally stupid. On the other hand it appears Sony might have been that stupid, so who knows what to assume about big companies who should know better.

I deleted the credit card from my Microsoft profile. There is a separate option to delete my address, which I also did. I got to my account settings by following this link: http://buy.officeformac.com/store/msmacus/DisplayHelpPage. Microsoft included this link three times — once misspelled — in the confirmation email for my purchase. If I didn't have that email handy, it's not obvious to me how I would have gotten to my account info by navigating Microsoft's web site. But I admit I didn't study the web site very hard.

. . .

UPDATE: I realized I should change my password. I'm keeping the email they sent me so I can show anybody who asks. No point keeping my real password around in clear text after complaining that's a bad idea.

Here is that email. It begins, "Thank you for contacting us on Microsoft Office for Mac US Store." What kind of sentence is that? Between this sentence, the misspelled URL in the confirmation email, and the officeformac.com domain name, I wondered for a moment if I'd carelessly made my purchase through a hacker site. But no, microsoft.com links to officeformac.com.

Clear text password

keyPathsForValuesAffectingValueForKey: — doing it wrong

I just noticed this in the docs for the keyPathsForValuesAffectingValueForKey: method:

Your override should typically invoke super and return a set that includes any members in the set that result from doing that (so as not to interfere with overrides of this method in superclasses).

I've been doing it wrong. I've been doing it like this:

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
    if ([key isEqualToString:@"fullName"])
    {
        return [NSSet setWithObjects:@"firstName",
                                     @"lastName",
                                     nil];
    }
    else
    {
        return [super keyPathsForValuesAffectingValueForKey:key];
    }
}

It didn't occur to me that a superclass might also want to specify key paths that affect the fullName key. A correct implementation would have been:

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
    NSArray *moreKeyPaths = nil;
 
    if ([key isEqualToString:@"fullName"])
    {
        moreKeyPaths = [NSArray arrayWithObjects:@"firstName",
                                                 @"lastName",
                                                 nil];
    }
 
    if (moreKeyPaths)
    {
        keyPaths = [keyPaths setByAddingObjectsFromArray:moreKeyPaths];
    }
 
    return keyPaths;
}

Serves me right for not reading the docs carefully. For pride's sake I was hoping this was a common mistake, but from a Google search it seems almost everybody else in the world does it right.

I must have been thinking of observeValueForKeyPath:ofObject:change:context:, where typically you check the given key path against various possible values and fall through to super if it doesn't match any of them.

In any case, I more often use the keyPathsForValuesAffecting<Key> approach anyway.

[UPDATE: Thanks to Christiaan Hofman for pointing out that my description of observeValueForKeyPath:ofObject:change:context: is also Doing It Wrong. So never mind that and pretend I wrote this instead.]

Being a CocoaHeads organizer

Last Tuesday, during the week of WWDC, there was a breakfast in San Francisco for CocoaHeads organizers, organized by Mark Aufflick, who runs the Sydney chapter, and hosted by Pivotal Labs. I got to meet Mark Dalrymple, the more visible cofounder of CocoaHeads ("AgentM" being the other). I got to hang with my friend Mike Morton, who organizes the NH/VT-ish CocoaHeads.

If we do this again next year (and I hope we do), I'll try to be more social. I didn't talk to as many people as I should have. I did meet the Boulder organizer and the former Taipei organizer. And I told a fellow from Sweden the one Swedish sentence I know ("Your wife is beautiful"). But there were lots of people I did not talk to. For example, I recognized but did not approach Graham Lee. It was a shame I didn't grab that opportunity to pick everybody's brains.

Among the people I did talk to, I noticed we all wondered the same things about each other:

  1. How big is your group?
  2. Is your group mostly about iOS?
  3. How do you get speakers?

Regarding question 1: I think a typical CocoaHeads-NYC meeting has about 15-18 attendees now that Google is hosting us. Maybe more. Ed Marczak, editor at MacTech magazine, is our sponsor. (On a related note, I want to thank Tekserve for kindly hosting us for a few years before we moved to Google.)

Regarding question 2: although many of us are iOS developers, our group has managed to stay focused on Cocoa. A lot of what we talk about translates to iOS, but I don't think we ever had an iOS-specific talk until last month. I haven't given much conscious thought to this, except to acknowledge that there are other meetups in New York that are iOS-specific, so there's no point in us being another one. And maybe the fact that I am not yet developing on iOS myself is a factor.

Regarding question 3: To me this is the most interesting question. I should probably be more systematic about getting speakers, but basically I wing it month to month. I've been lucky enough to get unsolicited volunteers along with friends who were willing to come up with something when I didn't have a speaker. On rare occasions I'll ask someone if they wouldn't mind presenting on a particular topic. And a few times I've either made myself the featured speaker or given a short talk in addition to a featured speaker's short talk.

Recently for a job I'm doing I learned about two new topics: Cocoa scripting and the keychain API. As I was taking notes, I realized I was itching to explain what I was learning to a group — partly just to share, partly to crystallize my own understanding, and partly so people can correct me where I misunderstand. When I get a chance, I'll prepare Keynote slides on these topics and hold them in reserve for when I need them.

Honestly? I would be perfectly happy to be the default speaker (or secondary speaker) at any given CocoaHeads meeting. But I want people to, you know, keep coming to our meetings, and it's safe to say they won't do that if CocoaHeads-NYC becomes The Andy Show. And besides, I learn such great stuff from other people. So I'll have to think about how to keep getting volunteers.

If you're a Cocoa developer in New York and there's something you'd like to present, let me know. It doesn't have to be fancy or super-advanced. It doesn't have to be a lecture — it could be a demo of an interesting project you're working on.

If you're a fellow CocoaHeads organizer, I'd love to know your approach to getting speakers. Do you ask what topics your members want to hear about? Do you have regular or semi-regular speakers? How far ahead do you schedule? Any other tips on running the group would be welcome too.