Response: Don’t Forget The ‘C’ in Objective-C!

RegDeveloper posted an article entitled Don’t Forget The ‘C’ in Objective-C!.

The premise of the article is reasonable: Remember that Objective-C has C underpinnings and that a number of common operations using, say, NSString can be orders of magnitude slower than a straight C based implementation.

Absolutely true. However, the article leaves out a critical step.

Measure the damned performance before applying error prone optimizations!

In particular, the article indicates that…

inside the internals of a certain Mac OS X utility – as one does. The programmer in question wanted to use OpenGL effects in his application, and in order to do that, he needed to establish the capabilities of the installed OpenGL system.

The article then goes on to call out the grossly inefficient use of NSString to check for certain OpenGL capabilities.

But, wait, so what? If this test is done once as the OpenGL code is initialized, it won’t even remotely register in terms of CPU cycles used or memory consumed. Bringing up the OpenGL stack, the various rendering buffers, and chunks of texture memory will be orders of magnitude more expensive.

Now, if said NSString based operation were sitting in the middle of a calculate-and-render loop then, sure, it could very likely be problematic. Maybe.

Who knows? Until you actually spend the cycles to measure the performance and determine where the bottlenecks lie, then any optimization is just wild-ass guesswork anyway.

Beware of any optimization article that does not start with analyze performance (or admit up front that it is a useless optimization designed to illustrate what might be useful in a real world situation).

Remember: A bubble sort is perfectly acceptable when sorting a dozen items once upon showing the info panel…. writing hand tuned assembly to solve that problem is simply mental masturbation. Nothing wrong with that until the project deadlines eat you alive.



15 Responses to “Response: Don’t Forget The ‘C’ in Objective-C!”

  1. Rosyna says:

    “NSString can be orders of magnitude slower than a straight C based implementation.

    Absolutely true. However, the article leaves out a critical step.”

    This is completely untrue. a straight C based implementation can be many orders of magnitude slower than an abstracted string type.

    CFStrings can be much faster at comparing compared to C strings as the former has a built-in hash (especially when they’re immutable). And copying a string is much faster using an abstracted/opaque string type than it is when using an array of bytes. Remember, the fasted copy is the one that doesn’t happen.

    Think about the most common operations when using strings. Which ones are faster when using an opaque data type that has optimizations for specific cases compared to what basically amounts to a bucket of bytes?

  2. bbum says:

    You missed the can in there. They can orders of magnitude slower, especially when dealing with goofy unicode.

    But, you are absolutely correct in stating that CoreFoundation, the Foundation, and other high level libraries have had the ever living piss optimized out of them. Not for all cases and there are certainly still some performance holes.

    Not the point, though. The article’s entire premise was about optimizing for a situation that, frankly, is a complete waste of time to optimize for. If it were an issue, the most likely optimization would be to move the bloody check-for-capabilities code out of whatever tight, likely render, loop it is sitting in.

    String operations be damned, don’t optimize something until you figure out that it is actually a performance problem!

  3. Rosyna says:

    I also said can multiple times.

    Are you saying abstracted string types can be slower or C strings can be slower when dealing with goofy unicode?

    Often, C strings are not appropriate when using Unicode. They don’t take normalization or case-folding or any of the other “goofiness” of Unicode into account. So when it comes to anything that isn’t ASCII, it’s not a matter of what’s faster or not, it’s what is appropriate.

  4. bbum says:

    No, I’m saying that I don’t care which can be slower until I actually figure out that string slowness is a performance problem in my application.

    In the context of the article, using NS, CF, or straight C API is almost certainly completely irrelevant to the performance profile of the app.

  5. Steve says:

    You’ve missed the point. The author’s idea was that Objective-C developers should keep in mind that you have C, and its library, as part of the language.

    As he admitted, this code is only used once and whether you do this with a strstr call or using NSString doesn’t really matter, at least from a performance perspective. That it’s a poor piece of code to optimize is less serious than the fact that his example doesn’t really establish, for me, that Objective-C people are forgetting about C. Perhaps that’s an issue; I wouldn’t know, not having touched the language in my life. Unfortunately, I still don’t know.

  6. bbum says:

    I stand firm by the opinion that any article claiming that a particular API or optimization should be applied without quite explicitly calling out the need to actually analyze said code in context of execution is misguided and, likely, incorrect.

    Barring that particularly huge flaw in the article, in this particular case — and as Rosyna also calls out — the higher level string handling APIs, be they NS or CF, aren’t really that slow and are often damned fast for particular cases while also avoiding the need to roll your own encoding handling code.

    The article is mediocre, at best.

  7. zachrahan says:

    Speed isn’t even an issue here. The article pointed to a four or five line stanza of code that could be replaced with a single function call. Ignore claims of speed, etc. (which the article didn’t really press), and what you have is a change whereby a relatively large amount of code in a “high level” API can be replaced by a lot less code in the “lower level API” because the impedances match (e.g. C string functions for C strings).

    All things equal, less code is more readable and less bug-prone. Now, not always are things equal, especially with regard to bug density (say the guy was talking about using strcpy instead of higher-level APIs)… But to read (and discard) this article as one about optimization is, I think, a mischaracterization.

  8. bbum says:

    Fair enough — I’ll certainly attest to the fact that people commonly use a hammer to drive a screw and avoiding that was one key subtext to the article.

    Still, optimization without analyzation is largely pointless. In that context, a simple “components separated by string” combined with “containsObject” is pretty damned simple/readable.

  9. zz says:

    All things equal, less code is more readable and less bug-prone.

    In this case, the strstr version *had* a bug as detailed in the comments. I also think it makes code a lot less readable if you mix C-style string api and NSString api in the same project. (especially when the C string api has method names such as “strstr” instead of “rangeOfString” like you have in nsstring).

    So the original longer version was more readable and less bug-prone IMO. Personally I would just check the OpenGL api for an existing ‘check for certain opengl extension” method.

  10. Vinpo says:

    This whole argument is nice and all as long as nobody uses it as an excuse to justify any lack of knowledge or skill. I’m not sure if anyone is doing this or not, but if you don’t know your TLB then study instead of making up excuses. Sometimes I wonder about the average education level of application programmers, I hope this is largely unjustified. A PhD doesn’t mean you must stop learning more things, ok?

  11. mikeash says:

    The original article “optimized” something that wasn’t a bottleneck down to broken code. The proper C equivalent to the NSString code is going to be at least as complicated, but we didn’t get to see it, because the article’s author was more concerned with speed than correctness. The original article was useless at best, dangerous at worst.

  12. Corey O'Connor says:

    “Measure the damned performance before applying error prone optimizations!”
    Indeed! Even designing for simplicity and clarity before optimizing can fail unless quantitative measurements are used to prove the optimizations. I now tell people to follow this, slightly ammended, philosophy:
    Rules of optimization:
    1. Don’t do it.
    2. Experts only: Don’t do it yet, and only if quantitative measurements exist to back up any claims.

  13. Jesse Tayler says:

    Bill has a really IMPORTANT point here, regardless of the example used, or the original article. I see programmers all over the place pronounce that “Oracle handles a tiny-int better than an unsigned int” or that “NSString is slow compared to some lines of assembly or lower level C. However, that fact is really not important if you see a whole project as something that must be maintained and delivered on time. Rarely are these “truths” about performance really behind performance problems in the real world use of a large scale project or system. Again, if you are not taking measures, you are not really focusing on where performance troubles lie and it is just that simple. Many engineers I’ve met do not like to be the “Scientist” part of a Computer Scientist, but without measures, tests and proof these “facts” about low level code elements are just tiny factoids that are not truly relevant to a project as a whole. I get the sense people like to show off their knowledge of these factoids, but do not like to set up Scientific measures and tests that concern the entire project. When you use Scientific measures, you basically never find out that it was the way you handled a string somewhere but rather you’ve found that a far larger paradigm or whole approach must be rethought and redesigned specifically.

  14. Jon Hendry says:

    To give the author credit, he does note that the code in his example doesn’t really need the change, and notes that such an optimization would make more sense in code that operates on non-Unicode strings in a tight loop.

    I think it can be marked up to the challenge of finding appropriately simple example code for the length and venue of the article. Ideally, it would have been example code that is in fact a tight loop. But that might have obscured things or required too much explanation.

    A better, longer article could probably be written which gives examples of falling back from Cocoa to all the various other apis: Carbon, Core Foundation, Quartz, Mach, BSD, etc in various contexts.

    But I don’t know if that would be appropriate for The Reg.

  15. Rich says:

    Premature optimizaiton is the root of all evil…

    –Donald Knuth

Leave a Reply

Line and paragraph breaks automatic.
XHTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>