New weblog!
[info]chanson
I've finally moved my weblog to my own domain! You can find it at http://eschatologist.net/blog/ now and probably forever.

I mostly wanted to wait until both WordPress and MarsEdit supported tags well, rather than just categories, and I wanted to wait until I could figure out how to migrate things easily. The latter I never really did; any migration I do is by hand, copying out of Xjournal and pasting into MarsEdit.

I've migrated many of my posts to the new weblog so far. I'll migrate more over time, and I'll fix up the internal links over time too. In the meantime, it's nice to be able to use MarsEdit to manage my posts, and to edit them as Markdown.

So update your subscriptions and be sure to stop by!

DDJ vs. Backyard Poultry
[info]chanson
Eric Sink has a post talking about the sad state of developer publishing, specifically discussing the declining readership of the venerable developer magazine Dr. Dobb's Journal, as compared to that mainstay of American newsstands Backyard Poultry.

After reading the article and the replies, I just had to throw in my two cents about magazine publishing and why "1% of the US population are software developers, so there should be a huge market for development magazines."

It's a significant mistake to think that the reader is the target and that the magazine is the product.

It is actually the aggregate readership that is the product, and the advertisers who are the target. That is, unless the magazine takes no advertising and is entirely supported by its subscribers.

This was driven home to me recently when I bought the recent "eInk Flashing Cover" issue of Esquire. I had never read Esquire before, so in addition to checking out the cool hardware on the cover, I started trying to read it. It was way more full of ads than Wired ever was — even in the days when Suck famously disassembled Wired 3.09 to remove the ads.

Furthermore, its advertisers were all very high-end. Thus I wasn't that surprised when I saw that the price on the subscription card for a year of Esquire was well under $1/issue.

So if Dr. Dobb's Journal is circling the drain, it's not the current readership that's to be blamed, or the Internet. It's the lack of advertisers interested in reaching that readership, or the magazine's ability to reach a readership that is interesting to a better-paying tier of advertisers.

Let's merge managed object models!
[info]chanson
There was a question recently on Stack Overflow asking how to handle cross-model relationships in managed object models. Now, the poster wasn't asking about how to handle relationships across persistent stores — he was asking how to handle splitting a model up into pieces such that the pieces could be recombined.

It turns out that this is somewhat straightforward to do using Core Data. Let's say you have a simple model with Song and Artist entities. I'll write it out here in a pseudo-modeling language for ease of reading:
MusicModel = {
    Song = {
        attribute title : string;
        attribute duration : float;
        to-one-relationship artist : Artist,
            inverse : songs,
            delete-rule : nullify;
        userInfo = { };
    };

    Artist = {
        attribute name : string;
        to-many-relationship songs : Song,
            inverse : artist,
            delete-rule : cascade;
        userInfo = { };
    };
};
Now let's say you want to split this up into two models, where Song is in one and Artist is in the other. You could just try and create two xcdatamodel files in Xcode, one with each entity, and wire the relationships together after loading them and merging them with +[NSManagedObjectModel modelByMergingModels:]. Except that won't work: Relationships with no destination entity won't be compiled by the model compiler.

What else might you try? You could try just putting dummy entities in for relationships to point to. However, merging models will fail then, because NSManagedObjetModel won't merge models that have entity name collisions.

It turns out, though, that you can merge models very easily by hand, by taking advantage of the way Core Data's model-description objects handle the NSCopying protocol. All you have to do is create your destination model, loop through every entity in each of your source models, and copy every entity that you haven't tagged as a stand-in using a special key in their userInfo dictionary.

Why does this work? The trick is that before you tell a persistent store coordinator to use a model, that model is mutable and references relationship destination entities and inverse relationships by name. So you can have only a minimal representation of Artist in one model, and a minimal representation of Song in another model:
SongModel = {
    Song = {
        attribute title : string;
        attribute duration : float;
        to-one-relationship artist : Artist,
            inverse : songs,
            delete-rule : nullify;
        userInfo = { };
    };

    Artist = {
        /* Note no attributes. */
        to-many-relationship songs : Song,
            inverse : artist,
            delete-rule : cascade;
        userInfo = { IsPlaceholder = YES; };
    };
};

ArtistModel = {
    Song = {
        /* Note no attributes. */
        to-one-relationship artist : Artist,
            inverse : songs,
            delete-rule : nullify;
        userInfo = { IsPlaceholder = YES; };
    };

    Artist = {
        attribute name : string;
        to-many-relationship songs : Song,
            inverse : artist,
            delete-rule : cascade;
        userInfo = { };
    };
};
Then, when you write some code to combine them, the merged model will wind up with the full definition of Song and the full definition of Artist. Here's an example of the code you might write to do this:
- (NSManagedObjectModel *)mergeModelsReplacingDuplicates:(NSArray *)models {
    NSManagedObjectModel *mergedModel = [[[NSManagedObjectModel alloc] init] autorelease];

    // General strategy:  For each model, copy its non-placeholder entities
    // and add them to the merged model. Placeholder entities are identified
    // by a MyRealEntity key in their userInfo (which names their real entity,
    // though their mere existence is sufficient for the merging).

    NSMutableArray *mergedModelEntities = [NSMutableArray arrayWithCapacity:0];

    for (NSManagedObjectModel *model in models) {
        for (NSEntityDescription *entity in [model entities]) {
            if ([[[entity userInfo] objectForKey:@"IsPlaceholder"] boolValue]) {
                // Ignore placeholder.
            } else {
                NSEntityDescription *newEntity = [entity copy];
                [mergedModelEntities addObject:newEntity];
                [newEntity release];
            }
        }
    }

    [mergedModel setEntities:mergedModelEntities];

    return mergedModel;
}
This may seem like a bit of overhead for this simple example. The critical thing to see above is that only that which is necessary for model consistency is in the placeholder entities. Thus you only need the inverse relationship from Song to Artist in ArtistModel. Say you wanted to add a Picture entity related to the Artist entity — you don't have to add that to both models, only to ArtistModel. The benefit of this method for merging models should then be pretty apparent: It gives you the ability to make your model separable, just like your code.

Erlang on LLVM? or: Outsource your JIT!
[info]chanson
Has anyone been working on using LLVM to do just-in-time code generation for the Erlang virtual machine?

Depending on the design and structure of the Erlang virtual machine, it doesn't seem like it would be all that tough a project. And it could provide a nice performance boost for those projects that are starting to use Erlang like CouchDB and ejabberd.

For an example of what I'm talking about, there's a project called VMKit that has implemented the Java and .NET virtual machines atop LLVM with reasonable performance. Essentially, if you have a virtual machine, rather than skipping either just-in-time or static code generation entirely, or trying to do it all yourself for some specific platform on which you want to run, take a look at what you can do with LLVM and see if you can leverage its code generation instead.

Not it!
[info]chanson
I didn't write Carrie's Dots — but I did download it!

It was written by Dr. Chris Hanson, a Chris Hanson who's evidently still in the mid-South. Maybe the next time I get a chance to visit [info]realgreendragon in Mississippi, we'll get to meet up!

LLVM terminology
[info]chanson
I thought the proper terminology was worth pointing out, since I've seen — and heard — some misuses lately.

LLVM is the Low-Level Virtual Machine and the project surrounding it.

LLVM-GCC is a compiler that uses GCC for its front-end and LLVM for its back-end.

Clang is the C language family front-end that is part of the LLVM project. It's a parser, semantic analyzer, and code generator — in other words, a compiler front-end that uses LLVM for its back-end.

The Clang Static Analyzer is what people have been trying out lately, to find subtle bugs in their and other projects. It's a great tool.

I just thought this was important to mention, because people have been referring to "LLVM" instead of "LLVM-GCC" in reference to the compiler included in Xcode 3.1, and people have been referring to "Clang" instead of "the Clang Static Analyzer" in reference to what they've been using to find bugs in their projects.

New bike! Marin Belvedere 2007
[info]chanson
I just got my first bike since junior high, and rode a bike today for the first time since high school! Many thanks to Meg for helping me pick it out and to Dan and others for listening to me ramble about what I might or might not want.

What I wound up getting was a 2007 Belvedere from Marin Bikes, in matte coal (of course). I test-rode it and it felt great, I could even shift — something I could never do in junior high or high school without losing control, damn post-shifters — and the only limit I felt with it was me!

So after accessorizing a bit, Meg and I rode home and then walked back to pick up the car. Cupertino and the South Bay in general are so bike-friendly I can tell I'm going to put a lot of miles on it just this summer, and if I get a good set of panniers there's no reason I won't be able to keep doing so into the fall and even winter.

And as tired as I am just from riding a couple miles today, it feels a hell of a lot better than contributing to the climate crisis while paying nearly $5/gallon for gasoline.

Always use notification name globals, not literal strings!
[info]chanson
What's wrong with this code?
- (void)registerForNotificationsFromTask:(NSTask *)task ( {
    [[NSNotificationCenter defaultCenter]
        addObserver:self
           selector:@selector(taskDidTerminateNotification:)
               name:@"NSTaskDidTerminateNotification"
             object:task];
}
If you didn't notice anything wrong, look again.

What's bad about this is that it's passing a string literal instead of a global variable for the notification name. The code should really look like this:
- (void)registerForNotificationsFromTask:(NSTask *)task ( {
    [[NSNotificationCenter defaultCenter]
        addObserver:self
           selector:@selector(taskDidTerminateNotification:)
               name:NSTaskDidTerminateNotification
             object:task];
}
Isn't that better? (Among other things, Xcode will offer to complete the NSTaskDidTerminateNotification global variable for you — unlike the contents of a string literal.)

This is a bug that often results from copying & pasting from documentation into code. "I need this notification, it needs to be a string, so I'll just put @"" around it." The type of a notification name is, in fact, NSString but you don't have to pass a string literal for that. Instead, pass the global variable that exists for each notification name and you're guaranteed that the right thing will happen.

If you're creating and using your own notifications, be sure to follow the Cocoa pattern and create your own global variables containing the notification name. Otherwise you're at the mercy of typos within string literals.

Update: Sanjay Samani helpfully pointed out that by constant string I meant string literal. Thanks, Sanjay! I've updated my post with this correction. (Not sure where my memory was…)

I fucking hate this city
[info]chanson
Meg rode her bike down from the hotel to Union Square to meet me for dinner, locking it up at a bike station right outside Borders.

After we walked back from dinner, we discovered it had been stolen. Right in the middle of dinner, right on the corner of fucking Union Square.

I fucking hate San Francisco. What a shit-hole of a city.

WWDC 2008
[info]chanson
The time is upon us once again — WWDC time!

As I have the past few years, I'll be in San Francisco all week, staying at the Hotel Kabuki in Japantown.

And of course, I'll be around the conference all week — especially in the labs. Come by and say hi, and I'll be happy to help with any questions you have!

No NSCoder night for me tonight!
[info]chanson
I'd like to make it to NSCoder Night tonight, but I just have too much else to do today — again.

I won't be seeing anyone at NSCoder Night next week, either, as I'll be in San Francisco for the Apple Worldwide Developers Conference! If you're attending, be sure to find me and say hi!

No NSCoder night for me tonight!
[info]chanson
I'd like to make it to NSCoder Night tonight, but I just have too much else to do today. Hopefully I'll see everyone there next week!

CocoaHeads Silicon Valley at Apple on Thursday, May 15, 2008
[info]chanson
The next CocoaHeads Silicon Valley meeting will be on Thursday, May 15, 2008 — that's tonight! — at 7:30 in the Garage 1 meeting room at Infinite Loop 4 on Apple's main campus. That's inside and upstairs at Apple's Infinite Loop campus in Cupertino. See the web site for directions.

This month's main presentation is on the Best of Both Worlds — an introduction to Cocoa development by Scott Stevenson.
This talk is a combination of an introduction to Cocoa, as well as a series of advanced tips and tricks that even relatively experienced Mac programmers may not know about.

The idea here is that we want to give all of the people who are new to Mac and iPhone development a chance to get started, but we also want to do something special for our advanced programmers. So rather than choosing one, we're just going to go ahead and do both.
Joel Norvell will also be presenting on how to edit PDF forms using Cocoa — he's done a lot of work with PDFKit and Cocoa, and I'm looking forward to learning from him.

Thanks a ton to Scott Stevenson, Steve Zyszkiewicz, Michael Jurewitz and Joar Wingfors for organizing!

In general, at a CocoaHeads meeting we do some introductions, have a presentation including Q&A time with the presenter, and then have an open Q&A and demo-your-cool-app period. After the meeting there's more independent mingling and discussion until it's time to go at 9:30. Often a subset of the meeting moves to BJ's Brewhouse in Cupertino, which is right in front of the Apple Infinite Loop campus on De Anza Boulevard.

Why is Twitter not just Jabber?
[info]chanson
Twitter is a way to post a short message to a wide group of subscribers, and to receive messages posted by a wide group of subscribers.

That's instant messaging. There's already a standard protocol for it: Jabber (XMPP).

Why not just use it? Why invent a new protocol?!

Actually, Twitter already does have experimental XMPP access to the full timeline — rather than to individual timelines, or to your friends' timelines — and you can use it to build things like TweetMaps and TweetClouds and Quotably and…

But Twitter should really be built entirely around XMPP. It shouldn't be a web app at all, though it could certainly have a web front-end. In case you doubt me, here's an example Twitter-like service implemented by Process One atop the ejabberd XMPP application server.

No NSCoder Night for me tonight!
[info]chanson
I'd like to make it to NSCoder Night tonight, but I won't be able to as I'll be looking at a new place. Wish me luck, and have fun everybody!

Build LLVM and clang!
[info]chanson
I've talked about the LLVM Compiler Infrastructure in the past, but what I haven't talked about yet is just how easy and quickly you can build it on your own Mac running Leopard! This is a great way to get into hacking on compiler lexical analyzers and parsers, code generators, optimizers, and so on.

What's more, you can build both LLVM and the new C front-end clang very easily and in five to ten minutes.

First, create a work area to check them out into, wherever you normally create your projects.
[~]% cd /Projects
[/Projects]% mkdir LLVM
[/Projects]% cd LLVM
[/Projects/LLVM]%
Then check out LLVM itself and clang from the LLVM Subversion repository.
[/Projects/LLVM]% svn checkout http://llvm.org/svn/llvm-project/llvm/trunk llvm
[/Projects/LLVM]% cd llvm/tools
[/Projects/LLVM/llvm/tools]% svn checkout http://llvm.org/svn/llvm-project/cfe/trunk clang
[/Projects/LLVM/llvm/tools]% cd ../..
[/Projects/LLVM]%
Then edit the PARALLEL_DIRS definition in llvm/tools/Makefile to tell it about clang. Just add clang onto the end, like this:
PARALLEL_DIRS := llvm-config  \
                 opt llvm-as llvm-dis \
                 llc llvm-ranlib llvm-ar llvm-nm \
                 llvm-ld llvm-prof llvm-link \
                 lli gccas gccld llvm-extract llvm-db \
                 bugpoint llvm-bcanalyzer llvm-stub llvmc2 \
                 clang
Now create a directory to build into, next to your llvm directory, and change into it.
[/Projects/LLVM]% mkdir build
[/Projects/LLVM]% cd build
[/Projects/LLVM/build]%
This is where you'll actually run configure. This will ensure your source tree isn't polluted with build products, and that everything stays self-contained while you hack.
[/Projects/LLVM/build]% ../llvm/configure --enable-targets=host-only
# lots of logging
[/Projects/LLVM/build]%
You'll note that above I passed an argument to configure. This ensures that LLVM is only built to target the architecture I'm running on, to speed up the build process; this is generally fine for simple front-end development.

Now, to build LLVM as well as clang all I have to do is invoke make. LLVM is set up to correctly do parallel builds, so I'll pass the number of CPUs I have in my machine via make -j 4.
[/Projects/LLVM/build]% make -j 4
# lots of logging
[/Projects/LLVM/build]%
That's it! LLVM is now (hopefully) successfully built. All of the pieces are in the build directory under Debug/bin and Debug/lib and so on; see the LLVM web site for details about what the various components are.

Copyright canonical form
[info]chanson
One thing that's nagged at me lately has been the series of applications I've seen lately with copyright statements that appear to be from the Bizarro universe. I don't mean that they have weird license restrictions; rather, they have a copyright statement in their standard About panel that's formatted strangely. It's a minor pet peeve to be sure, but it's a simple thing to get right and getting it wrong looks silly.

Note that the following is not legal advice on asserting or protecting your copyright — you'll have to go to a lawyer for that — it's just a suggestion on how to concisely format your statement that your work is covered under copyright.

In a Cocoa application, the standard About panel will show the copyright statement specified under the NSHumanReadableCopyright of its Info.plist file. This should generally be of the form
Copyright © «YEARS» «HOLDERS». All rights reserved.
where «YEARS» represents the individual year, set of years, or range of years during which the application was authored and «HOLDERS» represent the authors of the application.

Thus if I were to start writing an application in 2007 and finish it in 2008, I would put
Copyright © 2007–2008 Chris Hanson. All rights reserved.
in the NSHumanReadableCopyright key of its Info.plist file. (Yes, that's an en-dash between the years, option-hyphen gets you one.) It wouldn't have the year at the end, or random commas after things, or random abbreviations. Just one simple statement.

Someday I'll figure out how to add
Copyright © 2002–2008 Chris Hanson. All rights reserved.
to the bottom of my weblog, too. Hopefully in such a way that I can actually update it easily when the year rolls over…

CocoaHeads Silicon Valley at Apple on Thursday, April 17, 2008
[info]chanson
The next CocoaHeads Silicon Valley meeting will be on Thursday, April 17, 2008 — that's tonight! — at 7:30 in the De Anza 3 auditorium at Apple. That's just inside the south side of De Anza 3, right across Mariani Avenue from Apple's Infinite Loop campus in Cupertino. See the web site for directions.

This month's presentation is all about designing and implementing your human interface. User experience and human interface design are critical for Mac OS X software to get right. To that end, there's even going to be a UI makeover as Scott describes in his post on the meeting!

Thanks a ton to Scott Stevenson, Steve Zyszkiewicz, Michael Jurewitz and Joar Wingfors for organizing!

In general, at a CocoaHeads meeting we do some introductions, have a presentation including Q&A time with the presenter, and then have an open Q&A and demo-your-cool-app period. After the meeting there's more independent mingling and discussion until it's time to go at 9:30. Often a subset of the meeting moves to BJ's Brewhouse in Cupertino, which is right in front of the Apple Infinite Loop campus on De Anza Boulevard.

Down the Rabbit Hole: Four Years On
[info]chanson
Today was my four year anniversary working on developer tools at Apple.

No regrets about taking the red pill here!
Tags: ,

NeXTstation Color: Free to good (local) home
[info]chanson
I have a complete 25MHz NeXTstation Color that I want to get rid of to a good home — in other words, you should want to use in some capacity as a NeXT workstation, not make its case into art or something. This isn't some crappy PC of which there are millions with tiny variations among them, it's a workstation of which only a relatively small number were made.

Specifications:
  • NeXTstation Color
  • 17-inch NeXT Color Display
  • 16MB RAM
  • 400MB SCSI HD
  • NeXT Keyboard (non-ADB)
  • NeXT Mouse (non-ADB)
  • NeXT Sound Box
  • Appropriate cabling.
It worked the last time I turned it on, which was probably 2003. It's been in a box in my closet — the box the movers put it in when I moved out here four years ago. I don't see why it wouldn't work, but I wouldn't guarantee it. The motherboard battery will probably need replacing, for one thing.

Want it, and reasonably local to Cupertino? Ping me and we'll talk.

Update: The NeXTstation is claimed! Thanks for the impressive response — who knew so many people would want a workstation that's old enough to drive?