This post’ll be all over the map — there has been a lot of traffic on this subject. This stuff is particularly interesting to me. I have been banging out object oriented code for more than 20 years in a variety of languages — Obj-C since 1989. Thinking about this stuff is my day job, too. That rocks. Makes me really happy.
Daniel Jalkut recently wrote a post entitled “C is the New Assembly“. I’m not entirely sure what rock Daniel has been under for the last 20 years, but I’m pretty sure that C has always been considered to be little more than a portable macro assembly language by many folk for a long long time. I certainly remember such analogies being made when I first learned C.
Well, when I first learned C in a non-perverse environment. I learned C writing hypercard plug-ins. Yes, I learned C writing plug-ins for an application that only offered a Pascal API in an environment where pointers were often really pointers to pointers (handles) where the pointer would occasionally move out from under you. Fortunately, I was too ignorant to know that I was learning C the hard way.
But I digress. C has always been in the role of the “fallback for performance reasons” solution as soon as developers started writing significant bodies of code in other languages. Perl based CGI always had random modules written in C. Java has always had a painful native interface. C++ developers have long written chunks of code in C (though that has grown less common over time). Even the scripting languages all have supported dynamic loading from the beginning that has always been used for both accessing native functionality and for implementing “performance critical” stuff in native C.
Update: Daniel commented on this post:
I compare C to assembly completely apart from its rather coincidental technical approximations to assembly. I meant it on a much higher level. On a level where I hope in 10 years to be saying “Ruby Is The New Assembly.” It’s a coincidence that C is a relatively good alternative to assembler for producing highly optimized code. It’s still the case that C programmers “drop into assembler” when necessary to squeeze extra performance out of a particular platform.
Python is “close enough to C” that I suspect somebody in 5 or 10 years could say “Python Is The New C” and have a bunch of critics chime in “it’s been the new C for 15 years!” Well, not in my universe it hasn’t.
Actually, I think C developers dropped into assembly to squeeze out extra performance (or do stuff that wasn’t possible in C) more often in the past than they do now. The reasons are two fold:
First, fewer developers can effectively develop in assembly anymore. Not because programmers are dumber these days, but because writing assembly on modern CPUs is One Hell Of A Lot Harder than it was back in the 6502 or 68000 days. As well, modern codebases tend to be more portable even when only targeted to one manufaturer’s CPU — programming for a G3 vs. a G4 vs. a G5 could require very different low level code, if you were trying to eek out every last bit of performance.
Secondly, optimizing compilers have improved by leaps and bounds over the years. In particular, the optimizing part of the compilers are truly amazing chunks of linear algebra that do all kinds of subexpression optimization, execution reordering, and all kinds of relatively non-obvious tricks to make the code go really fast on modern processors.
Rare is the programmer that can effectively write assembly code on a modern CPU. Rarer still is the programmer that can write assembly code that performs better than that generated by a good compiler.
I agree with Daniel. I sincerely hope that we get to the point where “drop into primitive python” is an answer to various problems we are having in our highly abstracted programming environments of the future.
To get there, I think we will first have to get past treating software development like a specialized word processing exercise.
Daniel pointed to a post by Jesper called Take it to the Bridge that discusses a podcast with Gruber where he discusses the bridging technologies in Leopard.
Daniel said (which I ran into before I saw Jesper’s post, so I’ll respond to it here prior to Jesper’s post because, well, that was how my brain wen down this particular path):
He suggests that a typical developer will write everything in Ruby or Python, and then do performance testing. Anything that needs a speed-up can be redone in Objective-C. You know, that “slow” dynamic variant of C
This analysis is foreboding, because it’s exactly what programmers have always done when they switched to a higher level language.
Yup. It is exactly what programmers have always done. Lots of Objective-C programs have C or C++ engines under the hood for the “performance sensitive” parts. I put that in quotes because, more often than not, the optimization wasn’t necessary — it just added complexity for little or no actual performance benefit. Not always the case, but more common than anyone would care to admit.
And it is no different with Python or Ruby based GUI apps. Native code is commonly used for the performance sensitive parts. Of course, with PyObjC or RubyCocoa, much of the optimization-in-native-language has already been done because, after all, the python and ruby in said programs are typically just gluing together already existing native language frameworks.
If you think about it, a Cocoa app that is using — say — Core Data and Quartz Composer is consuming very little CPU in actual developer authored code. Most of the CPU time is spent in QC or CD either pushing data around or rendering graphics in 3D; 100s of thousands of lines of code being driven by relatively few lines of custom code found in the project.
Jesper says:
So at the end of the day, writing Ruby Cocoa apps is going to be a whole lot better and easier than writing Java Cocoa apps
Actually, that is the case now that RubyCocoa has evolved significantly in the last year and has been the case with Python via PyObjC for many years.
The problem with the Java Bridge is that it tries to make the Cocoa API look like a Java API. The end result is an API that doesn’t look like Cocoa and doesn’t feel natural to a Java programmer.
The RubyCocoa and PyObjC bridges don’t try to “mogrify” Cocoa into Ruby-esque or Pythonic APIs beyond a slightly syntactic adjustment to take the Objective-C interleaved method name and arguments style dispatch and turn it into the much more common call-it-like-a-function style dispatch. (No, for the last time, Objective-C does not have “named parameters”. Never did.)
Read the rest of this entry »