Cheap Yet Laudable Extravagance

April 14th, 2007

Today I would like to call out Google, and applaud them for continuing to support a wide variety of projects through their innovative Summer of Code micro-funding program.

This will be the third summer Google has offered a $4500 stipend to students willing to work “for free” over a summer on one of more than a hundred qualified projects. They also provide a nominal $500 “mentoring stipend” to the sponsoring project, for each student.

It would be easy to dismiss this is a cheap way for Google to promote development in open source projects from which they take value, while enhancing their reputation among the developer public, and also indoctrinating the loyalty of a bunch of students who will soon be entering the work force.

It is all of those things, but it’s also something wonderful. The list of projects this year number over 130, and the list of students over 900. If you do the math, you realize that Google will spend as much as $4.5 Million on the stipends over those few summer months (the full stipend amount is only paid if the student’s work is deemed “passing” by the mentoring organization). One only needs to look at the breadth of projects being sponsored to realize that while Google may benefit from the net rewards of the program, there are many other organizations and people who benefit as well.

$4.5 Million is a lot of coin, but in the context of the billions in revenue that both come into Google and go out of Google in the form of acquisitions, the money is chump-change. For chump-change, Google realizes it can dramatically affect the development momentum of 130 projects, give 900 students a sense of pride and experience in a team-working environment, and endear the development world to their good deeds. That kind of equation makes this investment a no-brainer for the corporate behemoth.

On a philosophical note, what kinds of cheap yet laudable extravagances can you afford to share with the world? It might be only answering a question on a mailing list, or sharing a bit of tricky source code. Google reminds me that we don’t always have to sacrifice much to benefit much. And our peers will applaud us, too.

Leopard Isn’t The Problem

April 12th, 2007

Apple announced yesterday that Mac OS X 10.5, code/marketing-named “Leopard,” will not ship in Spring as promised, but will instead ship in October. (Confoundingly, the “Hot News” item at Apple doesn’t even have its own link, naked among the other public relations tidbits. Perhaps a sign that they’re not proud of the statement).

The announcement caps off a season of speculation alleging fluctuations in Leopard’s ship date. While early 2007 brought us lunatics predicting a March release, more recent speculation has hinted that a substantial delay was inevitable. This theory was soundly rejected by Apple less than three weeks ago, in a response to what turned out to be quite an accurate preview of the brutal truth.

The news has inspired reactions by respected Mac OS X developers (Gus Mueller, Brent Simmons, David Weiss, among others) and users (David Chartier, John Gruber, the Macalope, and many, many others). But while these people offer intelligent views on the relative pros and cons of the delay and its consequences to ordinary people, I don’t see much reaction to the core problems in Apple’s confession. I envision a bunch of PR folks sitting in an office toiling with the fact that they’ll have to break this unfortunate news. What to do, what to do. One of them has the brilliant idea that they can simply “blame” the iPhone. By blaming a problem on what’s widely perceived by the public to as a success, it will somehow make the company appear mature and well-reasoned in its decisions. Something more excusable than a company that occasionally fails to work a miracle. And somehow this idea made its way through some review process and all the way to public release. In stark contrast to Steve Jobs’s brilliantly candid Thoughts On Music, this statement sounds made-up and poorly thought-out. Bluntly crafted, sleazy marketing bullshit.

The best we can hope for is that it is only sleazy marketing bullshit. Because if what Apple’s telling us is true, then they’ve confessed something tragic: they’re incapable of building more than one amazing product at a time. The iPhone looks like it will be an amazing product, but if Apple can’t keep an OS team focused and operational at the same time as they keep a cell phone team hacking away, then the company is destined for extremely rough waters as it attempts to expand the scope of its product line.

What happens when the phone takes off, and Apple’s stuck following through on their Mac OS X commitments? “Sorry, no iPhone 2.0 until 2009 – we’ve had to move everybody back to OS X!” Needless to say, even with the apparent comingling of iPhone and iPod technologies, this situation leaves me unable to speculate as to when a dramatically new iPod might find time to be developed in this environment.

If Apple is truly so strapped for talent that they can’t focus on more than one product at once, then it’s a symptom of a sickness within the company. Perhaps they’ve regained success too quickly. If a company with a market capitalization of $80 Billion, and a cash account of at least $6 Billion, cannot hire enough people to build three of the hottest, most demanded products in consumer electronics (the iPod, the Mac, and the iPhone, if it’s not obvious), then maybe it’s time to reevaluate their modus operandi for attracting and retaining talent.

The first thing Apple should do is go global. Their products are universally renowned, yet the company requires the vast majority of its engineering teams to live and work in California – in a suburban, high-cost area of California, at that. Sure, Apple has a few small teams scattered around the world, but mostly as side-effects of specific acquisitions. The message to all Mac developers I know is being heard loud and clear: if you want to be part of this revolution, you’ll have to move to Cupertino. By limiting the company’s ranks primarily to those people willing to live in this one particular geographical location, they shut down their ability to attract a huge number of talented individuals.

If Apple’s having trouble growing its ranks of geniuses, the solution may require something that no amount of cash or stock can buy: a change of attitude.

Abusing Objective C With Class

April 12th, 2007

Dynamic messaging is one of the nifty features of Cocoa and Objective-C programming on the Mac. You don’t have to know which class, or even which method your code will call until runtime. The feature is utilized a great deal by the delegation pattern employed by most standard classes in AppKit. For instance, when a window is threatening to close, Apple yields the final decision making to a delegate method, if present:


- (BOOL) windowShouldClose:(id)sender;

If you implement this delegate method and return NO for a particular window, then the user’s attempts to close it are thwarted (hopefully because you just did something friendly like ask them if they were sure or not).

If we’re agreed that delegation and dynamic messaging are a good idea, we should be prepared to use them in our own code as well. Let’s say we’re writing a custom class where delegation of this kind would be useful. We’d like to be as much like Apple as possible, to further solidify the patterns that we all use on a regular basis.

My example application is a coffee maker, and it makes coffee at regular intervals unless the delegate method believes it should not:


- (BOOL) coffeeMaker:(RSCoffeeMaker*)theMaker
	shouldBrewForScheduledDate:(NSDate*)scheduledDate;

What must the code in the coffee maker do in order to satisfy this contract? The “scheduledBrewTimerFired:” method might look something like this:


- (void) scheduledBrewTimerFired:(NSTimer*)brewTimer
{
	BOOL shouldBrew = YES;
	
	// Give the delegate a chance to reject
	SEL delSelector = 
		@selector(coffeeMaker:shouldBrewForScheduledDate:);

	if ((mDelegate != nil) &&
		([mDelegate respondsToSelector:delSelector] == YES))
	{
		shouldBrew = [mDelegate performSelector:delSelector
			withObject:self
			withObject:[brewTimer fireDate]];
	}
	
	if (shouldBrew == YES)
	{
		//...
	}
}

Nifty, right? Yes, nifty. But wrong. What’s the problem? It’s that line where performSelector is called. If you have as many warnings turned on as you should, you’ll see something along the lines of “warning: assignment makes integer from pointer without a cast.” The reason? The performSelector method returns an “id”, not a “BOOL”. We’re expecting magic to happen here, and those of us who grew comfortable with the nuances of PowerPC-based calling conventions have seen magic happen here more often than is healthy.

By violating the function prototype for performSelector, we’re robbing the compiler of its ability to accurately produce assembly code that retrieves the BOOL return type correctly. That means we’ll get the wrong answer some percentage of the time, where that percentage is determined by the degree to which BOOL and id return types are handled differently on the platform.

My first instinct in addressing this problem was to go down a layer. Surely if performSelector is using an unsatisfactory prototype, I could just drop down to objc_msgSend and handle the messaging myself. But alas! The lower-level function also returns an id. At this level, there are some special functions such as objc_msgSend_stret, which messages an object and returns a structure, but there isn’t a handy objc_msgSend_boolret for our convenience.

So what’s a conscientous developer to do? I was lucky to discover a mailing-list thread, in which the answer to this question was beautifully outlined by Greg Parker of Apple. Credit also goes to Rosyna of Unsanity, for asking the question that led to Greg’s answer. Rosyna later expressed appreciation in a follow-up post.

So what’s the trick? In order to get the freedom of dynamic messaging combined with the complete cooperation of the compiler, we need to define a custom function pointer. This points to the same address in memory as the objc_msgSend function, but is defined with a differing prototype. This way we get the message delivery functionality of the Objective-C runtime, while letting the compiler in on the fact that the method being messaged will in fact return a BOOL typed response.


#import <objc/objc-runtime.h>

- (void) scheduledBrewTimerFired:(NSTimer*)brewTimer
{
	bool shouldBrew = YES;
	
	// Give the delegate a chance to reject
	SEL delSelector = 
		@selector(coffeeMaker:shouldBrewForScheduledDate:);
	if ((mDelegate != nil) &&
		([mDelegate respondsToSelector:delSelector] == YES))
	{
		// Give the compiler a clue - courtesy of Greg Parker
		BOOL (*MyMagicSender)(id, SEL, id, id) = 
			(BOOL (*)(id, SEL, id, id)) objc_msgSend;

		shouldBrew = MyMagicSender(mDelegate, delSelector,
			self, [brewTimer fireDate]);
	}
	
	if (shouldBrew == YES)
	{
		//...
	}
}

Nifty, right? And correct, too. Enjoy!

Update: Paul Kim via chat, and Jan Van Boghout in the comments below each noticed a flaw in my contrived example. Since I already know the selector I’m planning to call, I could just define it explicitly with a regular Objective-C method prototype. Then the compiler would know exactly how to generate the code if I called the delegate directly:


shouldBrew = [mDelegate coffeeMaker:self
	shouldBrewForScheduledDate:[brewTimer fireDate]];

That’s true, and it’s a fault in my overly-contrived example. But imagine a more dynamic scenario, where the prototype of the method is known, but not the selector. For instance, if the class offers clients the ability to specify a selector:


- (void) scheduleBrewingAtDate:(NSDate*)brewDate
	withBrewDelegate:(id)brewDelegate
	withDelegateSelector:(SEL)delSel;

Are You Feeling Lucky, Punk?

April 11th, 2007

In the years since I first started developing FastScripts, all manner of keyboard-shortcut type solutions have popped up, including the enormously ambitious Quicksilver, and the refined, trigger-action-oriented Butler.

But some of us still appreciate FastScripts for its simplicity. Put scripts in the standard Apple-location, cmd-select them from the FastScripts menu, and assign a keystroke. FastScripts could be improved in some important ways, but it’s been in “stable and revered” mode for years now, which has made it a reliable tool for people to recommend to others. I think it’s easy to recommend because it does exactly what it says it will do, and little more. You don’t need to join a FastScripts cult or change your entire workflow to get some use out of it!

Michael Tsai recommends it in the manual to his BBAutoComplete product. I see frequent referrals from Quark and InDesign forums, where running scripts efficiently is a major part of the creative and production process. It’s gratifying to know that FastScripts has become a part of the productive environment for so many people.

But sometimes people just use it because they feel lucky. Christopher Biagini shares his I’m Feeling Lucky script, which performs a simple but useful task. It asks you for a phrase, then it does the Google search for you, then it takes you straight to the “I’m Feeling Lucky” link. I clicked the handy “open it directly” button which worked like a charm to bring it to Script Editor. Then saved it to my Scripts folder and assigned a keystroke. Nifty! And a lot lighter-weight than Google Desktop :)

Go ahead, make my day. Give FastScripts a try!