Alastair’s Place

Software development, Cocoa, Objective-C, life. Stuff like that.

iPhone UK

Well, it’s official: iPhone will be here on November 9th, on O2.

There are already some silly remarks flying about the £269 (inc. VAT) price being higher than the current U.S. $399 price, but of course it isn’t significantly higher once you take account of VAT.

As for the 3G versus EDGE question, we’ll have to wait and see how that pans out, I think. 3G coverage in the U.K. is a whole world better than EDGE right now, so it’s a bit of a shame that they aren’t launching a 3G iPhone, but they’re right about the battery life issue, and O2 at least has its own WiFi network, which we’re told will be available to iPhone customers without those annoying web forms.

Will I get one? I’ve been pondering that question for some time. I think I’ll wait for the next model, or maybe the one after that. That’ll give Apple a chance to release a 3G model with more storage, and it’ll give the mobile companies a chance to improve their WiFi, EDGE and/or HSDPA coverage.

“Environmental Groups” Pull Out of Nuclear Debate

According to the BBC, Greenpeace and Friends of the Earth have pulled out of the British Government’s consultation on whether or not the U.K. should build more nuclear power stations, claiming that it is not a “fair and full debate”.

Of course, what they really mean is that they aren’t winning the debate, which I have to say I don’t find terribly surprising (especially as a number of prominent environmentalists are on record as supporting nuclear power). A lot of environmentalists are misinformed or even wilfully ignorant about the issues they wish to “debate”, and when challenged on the subject by someone who does have the facts, they either pull out the “precautionary principle” and claim that the other party cannot be aware of all possible consequences (which is true, but their version of the precautionary principle would have us all confined to underground bunkers for fear of asteroid strikes1), or—as in this instance—run away from the debate claiming that it “isn’t fair”.

Frankly it’s pathetic.

1 This is the reason that I dislike the “precautionary principle”. The original idea was that you should, when making a decision, take account of any risks inherent in that decision. Which, frankly, is what any sane person would do anyway (which begs the question, why do we need a name for this practice?!). But it is often trotted out and used in the sense of “we must not do that because there is a risk, however slight”, which is just plain crazy.

MarsEdit and UTF-8

That last post wasn’t made with MarsEdit (because I wanted to test MovableType itself), but this one is, so here’s “Hello World” as translated by Sherlock into a few different languages.

你好世界
Hello Wereld
Bonjour Monde
Hallo Welt
Γειάσου κόσμος
Ciao Mondo
こんにちは世界
여보세요 세계
Hello Mundo
Здравствулте! Мир
Hola Mundo

I’m sure this will work fine, but if it doesn’t for some reason, it’s probably Perl’s fault :-)

MovableType and UTF-8 (Again)

Hopefully I’ve now got UTF-8 support working, after upgrading DBI and DBD::mysql and adding mysql_enable_utf8=1 to the DSN in lib/MT/ObjectDriver/DBI/mysql.pm. However, we’ll see.

Just to make it obvious if it’s broken: åéîøü

Yep, it seems to work. I’ve been struggling with that for ages now, on and off, as it’s been a real pain having to enter ’ every time I want a nice looking apostrophe/close-single-quote. Of course, I’ll now have to adjust to actually typing the “ ’ ” character.

Testing MarsEdit 2.0

I tried MarsEdit a while back, but I didn’t see a significant advantage in using it over MovableType’s built-in post editor. Of course, I wasn’t blogging much back then…

However, Daniel Jalkut just released MarsEdit 2.0, so I thought I’d give it another try. I’m going to write my next few blog posts using MarsEdit to see if I like it. My guess is that I probably will.

Already I see things that I like very much—like the preview window. That’s a really nice feature, because it lets me see in advance how a post is actually going to look on my site. My guess is that pretty soon, $30 of my hard-earned cash is going to be winging its way on its long journey towards Daniel’s pockets :-)

Connectivity Hell

On Friday, my ’Net connection started bouncing up and down every minute or so. Obviously this isn’t supposed to happen, and this is the second time now that it has. Unfortunately, working from home, I rely on my ’Net connection working.

To their credit, Plus.net have always answered the phone promptly and have tried to help, as much as they can. I don’t actually think it’s their fault though. Most likely (particularly as it happened on a Friday last time too) it’s one of BT’s engineers doing something on a Friday at our local exchange.

Anyway, I’ve pretty much made up my mind that I need an office. Extra expense, obviously, but at least it means I’m not reliant on my home broadband connection.

(It has got a bit better, in that it’s now up and down every five minutes or so, rather than every minute, but even so it makes things rather awkward…)

NSCell and Overriding -objectValue

It’s sometimes tempting when writing a cell class to override the -objectValue and -setObjectValue: methods of NSCell and let something other than the cell store the value (perhaps you could even generate the value from some other data).

But please don’t.

The problem is that NSCell doesn’t use the -objectValue accessor in some important cases1, which means that if you override -objectValue, some of the cell’s methods will produce inconsistent results.

The right way to use NSCell is to always let NSCell store the data, which will avoid significant pain if someone is trying to do something fancy in a subclass of your cell.

1 For instance, in the private _stringForEditing and _attributedStringForEditing methods, which are used to get the string to put into the field editor if you’re using NSCell’s text editing support. Arguably the fault here lies with NSCell, but either way, there are no problems if you let NSCell store its own data.

Optimization Without Measurement - a Seductive Trap

Readers of Apple’s cocoa-dev mailing list will have seen a number of messages recently attacking the Objective-C feature of making messages to nil do nothing.

One of these posts (whose author shall remain nameless) made the claim that

…it’s disappointing that people still think that it’s quicker to just send the message to nil, than to do “if (target) [target message];” since it doesn’t matter how fast you make that message dispatcher, it can’t possibly be faster than the two instructions that the conditional takes…

These kinds of arguments are a very seductive trap for the unwary programmer; they seem “obvious”, right? Nevertheless, as I’ll show, they aren’t always as clear cut as they first seem.

If you are considering optimizations to your program (and you should), you absolutely must measure to see where you should spend your time. Indeed, if you write programs for Mac OS X, you are spoilt for choice in terms of the tools available to help you do this. (I’m a particular fan of Apple’s Shark tool… it’s a large part of the reason that iDefrag’s main display is so fast.)

With that in mind I decided to measure the function call overhead both for Objective-C messages and for a few other common types of function call. Apple don’t have anything specific that can help out with this type of measurement, so I fell back on a simple C test rig. I’m not going to reproduce the code for my complete test here, but I will give you a flavour:

#include <sys/time.h>
#include <stdio.h>

static double
hires_time(void)
{
  struct timeval tv;

  gettimeofday (&tv, NULL);

  return tv.tv_sec + tv.tv_usec * 1e-6;
}

#define ITERATION_COUNT 10000000

int
main (void)
{
  double elapsed;
  unsigned n = 0;
  volatile unsigned a = 0;

  elapsed = -hires_time();
  for (n = 0; n < ITERATION_COUNT; ++n) {
    /* The thing you're timing goes in here */
    ++a;
  }
  elapsed += hires_time();

  printf ("Incrementing a variable in memory takes %g ns.\n",
          (elapsed / ITERATION_COUNT) * 1e9);

  return 0;
}

(Note that you may have to be careful when compiling test rigs like the above to make sure that the compiler’s optimizer doesn’t optimize away the thing you want to test. Be very wary about any unexpectedly fast results.)

Anyway, back to the nil issue. For my test program, my Mac Pro (3GHz Dual-Core Xeon) reports the following results:

Message sends take 5.34852 ns.
Nil sends take 6.01709 ns.
IMP sends take 2.67442 ns.
Function calls take 2.00583 ns.
Dylib calls take 2.67425 ns.
Virtual function calls take 2.33997 ns.

A nearby G5 machine (2.3GHz G5) reports:

Message sends take 15.6726 ns.
Nil sends take 9.14313 ns.
IMP sends take 4.35283 ns.
Function calls take 3.91874 ns.
Dylib calls take 7.83509 ns.
Virtual function calls take 5.87761 ns.
</blockquote></blockquote>

These numbers are timings for a call and return to an empty function/method, averaged over 10 billion calls (yes, billion).

Obviously this is an artificial benchmark, but the long and short of it is that message sends are fast. Not as fast as a plain C function call, perhaps, though using an IMP you can get them to go as fast as a call to a function in a dylib, or even faster on PowerPC machines.

The difference between

if (foo)
  [foo bar];

and

[foo bar];

is very small; according to my measurements, on the G5 it increases the time taken for a non-nil send by 1.3ns and reduces the cost of a nil send by around 7.8ns. For this to be a net gain on the G5, therefore, more than one in six of your message sends would have to be to nil.

On the x86 machine, the time taken for a non-nil send increases by 0.33ns, and we reduce the cost of a nil send by 5.7ns. For this to be a net gain, more than one in seventeen of your message sends need to be to nil.

Are one in six message sends in a typical application to a nil object? I doubt it. How about more than one in seventeen? It’s possible, but in high-performance code (the only place this kind of saving would ever matter) it seems unlikely.

Even if you removed the nil checks from the Objective-C runtime, you’re only going to make the non-nil message sends faster by a tiny amount, and for what? You would have to add tests all over the place for nil, and performance critical code won’t ever care anyway because it will be using IMPs or C functions. So all you’d have done is made it more likely that the end user will lose their data when a nil does turn up unexpectedly. Before the change, your program might have behaved oddly (though there’s a good chance it would have let them save their work). Now it will crash instead.

Perhaps you could have some sort of error handling routine that triggered on a call to nil, but then the runtime needs to check for nil again, so you’ve erased the saving. On top of that, you’ve made all of your code more complicated in the process, and as a result you’ll now be paying a penalty because branch prediction won’t work as well with thousands of “if” statements as opposed to the one branch in the runtime.

The point? There is no credible performance argument for sends to nil being anything other than a no-op. Even a lot of supposedly high-performance code doesn’t need to shave off the few nanoseconds that you might save, and that’s only if messages to nil are more common than the figures above, or if you’ve modified the runtime and accept that messages to nil will cause an outright crash.

In fact, even though it has some justification (because there will be fewer conditional branches in ordinary code), there is no real performance argument in the other direction either; you simply don’t need those few nanoseconds. In the few cases where you might care, you won’t be writing your code that way anyway.

Our Products

My friend and colleague Chris Suter (who you may know from his regular posts on the cocoa-dev and xcode-users developer mailing lists) thinks I should mention our products more on my blog.

He’s probably right; after all, iPartition and iDefrag are pretty useful programs, and both of them have a number of unique features not found in anything similar on any platform. Mind you, just wait until you see iPartition 2.0 when we release it :-)

I promise, by the way, that this blog isn’t going to turn into a stream of advertising for our software. That’s just not interesting. But perhaps I’ll talk more about new features when we add them.