Apple introduced Swift as “Objective-C without the C”, but in many ways, Swift is closer to “C++ without the C” (or Objective-C without the Smalltalk). Swift’s generics, for example, are closer to C++’s templates than to any feature of Objective-C. One of the more subtle ways that Swift resembles C++ is in how it calls methods. Unlike Objective-C, where methods are called using message passing, Swift uses a vtable for method dispatch, and when the compiler has enough information, inlines the function call directly. While this improves performance over message passing, it trades power and flexibility for performance gains that aren’t necessary for most apps.
In this article, I will present use cases which are currently impossible or difficult to implement without message passing.
Objective-C isn’t going away any time soon, but if Swift succeeds in becoming the dominant language for iOS and Mac development, Objective-C will go away. Eventually the cost of maintaining two languages and runtimes will cease to be worth it. Like Carbon before it, Objective-C will be deprecated, leaving Swift as the only supported language for app development on Apple platforms. In general, I am loathe to argue that my way is the one true way to do things, but since Swift will eventually be the one way to do things, and since now is the time when large changes will be easiest to introduce, I feel compelled to argue that Swift should forswear all but message passing.
On the Mac, swizzling is used to implement plug-in functionality, even for apps that don’t have a plug-in API. This adds features that are very important to power users. Many popular Photoshop and Xcode plug-ins use method swizzling. GPGMail, a plug-in for Mail.app which adds OpenPGP encryption to Mail.app, makes extensive use of method swizzling. This functionality is incredibly important to security-minded individuals, especially in the wake of the Snowden leaks. If Mail.app were rewritten in Swift, this would not be possible.
Swift already does have a way to opt-in to message passing, it’s called the @objc flag (and performSelector:). It works fine, but it’s extra work to opt into it and use it. But, I don’t think that’s bad given that it disables so many useful optimizations.
What may be bad is that the name “@objc” is a dead giveaway that this is a feature with a deprecation date. So I think we need some other, reflectionish system going forward.
My argument is that Swift will be primarily used to write high-level apps. For these apps, message passing is almost never a bottleneck. Swift is not going to replace the optimized C and C++ code, especially for the really low-level stuff.
But even if Apple does decide to rewrite all the Core* frameworks et. al. with Swift, there’s still an argument that Swift should use message passing by default, and a way to opt in to vtable and direct dispatch for performance-critical code. For higher-level apps, message-passing is a lot less useful if it’s opt-in.
To me it looks like replacing ObjC and the frameworks (over time) and the style that puts everyone on an equal footing. So instead of having a language where anyone can build something like Core Data, you will have a language with built-in support for Core Data. Apple’s Core Data, that is, and you will like it. Just another tightening of the screws (App Store, App Store–only APIs despite promises).
In the rare occsion that objc_msgSend is a bottleneck in an Objective-C app, there are techniques like IMP caching that can improve performance, and that’s really the kind of thing I’m advocating here. Give developers some way to opt in to vtables when there’s a real performance problem, but allow the greater flexibility of message sending by default. It’s possible to start with message passing and optimize when needed, but it’s not possible to start with vtable dispatch and use message sending when needed.
Message sending allows many problems to be solved with much less code. This increases programmer producivity and lowers maintenence costs. Since message sending is fast enough in most cases, the end user sees no difference between vtables and message sending, so Swift should use the solution that results in better programmer productivity.
Stay up-to-date by subscribing to the Comments RSS Feed for this post.