There’s a “discussion” on Usenet right now about the relative merits of Objective-C versus C++. I know better than to post to that sort of thread on Usenet, but apparently I don’t know better than to do it in my weblog.
The argument (which you can go and read yourself) boils down to “C++ can do everything Objective-C can” versus “sure it can, but not easily, usably or understandibly.” The usual argument comes down to object models: With Objective-C, you can send any object any message, and if it understands it, it will respond. C++ is restricted by its compile-time type system, so that even if you have arbitrary objects that all implement the member function
foo, there is no way to call that method on a set of them unless they all inherit from the same base class. Except that you can, as exemplified
To me, here’s the point people are missing: Objective-C has one main model for programming, objects. C++ has two. It has its object system, which is very different than Objective-C’s. C++’s object model simply does not allow you do to the sort of messaging and introspection that Objective-C allows. But C++ has another, far more powerful, programming model: generics (aka templates). With a template, you can call
foo on any object that implements it, regardless of class hierarchy. just method signatures. That’s how
boost::variant works, behind the scenes. In fact, it’s even more powerful, since you can make use of any property that’s shared between two types, not just method names. Generic programming, when you make full use of it, provides object-like polymorphism and overloading without using objects. Note that the STL makes use of inheritance only for code reuse, and classes only for encapsulation. In an interview on the design of the STL, designer Alex Stepanov recommends against member functions, instead recommending that all methods be global.
Thinking about, I realize that well-designed class libraries for each language look completely different, object-wise. A template-based C++ class library (like the STL) makes heavy use of inheritance for code reuse, but does not use dynamic method dispatch (“
virtual“) for polymorphism, relying on templates instead. An Objective-C class library (e.g., Cocoa) uses objects for polymorphism, making heavy use of dynamic dispatch but without much subclassing; code isn’t inherited from one class to another, but classes delegate to one another to share code. This is true even (or especially) compared with non-template-based C++ class libraries. For example, in PowerPlant (a C++ app framework for the Mac), most classes are designed to be subclassed. Your app might inherit from LApplication and implement methods to customize it. Very few of Cocoa’s classes are ever subclassed, on the other hand; an app would implement a separate delegate class that responds to events or answers questions that NSApplication asks about how your app should behave.
Then there’s Java, which is stuck with the inefficiencies of Objective-C’s runtime object model (and lack of generics), but the rigidity of C++’s compile-time type system. When using a Java class library, you can’t simply inherit all the code you need as you might with C++, since Java only has single inheritance, but since it has strong type-checking, you can’t use Cocoa-style delgation either. Last time I did serious Java programming (it was several years ago), I remember having to create dozens of “connector” classes just to implement the interfaces that the APIs needed. Java 1.1’s big new feature was “inner classes”, which did nothing to solve the serious language problem, but at least made it so that you didn’t have to create a separate source file for each of these damned things. I hear that Java is getting “generics” support soon (if it hasn’t already), but my understanding is that it’s just templatized types, which mainly just means you can write type-safe code using off-the-shelf collections without casts. It doesn’t give you any of the expressive power of real generic programming (e.g., C++ templates). Java, under the hood, does use an Objective-C style object model, but you need to use the reflection APIs to get access to it, and they aren’t very “natural” (and weren’t added until Java 1.1, either!) In Objective-C, you can call a method on an object not known to implement it until runtime, simply by calling it.
Once again I’m not quite sure what my point is. I do know that C++ is a far more complicated language than Objective-C. Every time I look at code that makes heavy use of the C++ language, I find out more things that can be done with it. With enough application of template magic, C++ can in fact do almost any language trick, and it is compile-time checked and type-safe in situations where almost any other language would have given up even run-time type safety miles before. Years after I thought I knew everything in the language, C++ continues to impress me with the things it can do. I think there’s something really poetic about a language that’s deep enough that no one can ever fully understand it. On the other hand, when I need to get something done, I’m usually more interested in working code than poetry.