Carbon and Cocoa as a Metaphor for Objective C and Swift

July 21, 2014

In the two most recent episodes of Core Intuition, Daniel Jalkut and Manton Reece talked about whether Swift will split the Apple third-party developer community into Swift and Objective-C sub-communities. Manton pointed out that the community was split in the early 2000s between Carbon and Cocoa, and although people tend to perceive OS X as a continuation of NeXTSTEP, it’s actually, “a beautiful mix of classic Mac, NeXTSTEP, and new stuff”. Should Mac and iOS development similarly become a beautiful mix of Objective-C and Swift, we can look forward to a smooth and eventual transition to Swift, but at the end of that transition, we may be left with large Objective-C apps that, like Carbon apps today, are increasingly out of place on Apple’s platforms.

The Legacy of Carbon

It’s amazing how well the Classic to OS X transition worked because of Carbon. Although some developers were unable to make the transition from Classic Mac OS to OS X, most of the important apps were able to transition without requiring disruptive and major rewrites. These apps may not have made it to OS X otherwise. However, the choice to migrate code to Carbon rather than to rewrite it in Cocoa may have created more work for those developers in the long run.

Carbon was created to allow Adobe and Microsoft to easily keep their flagship products on OS X. Office and the Creative Cloud apps are large C++ codebases, mostly because they share a lot of code with their Windows versions. As Apple has rolled out new technolgies that improve their platforms, these apps have struggled or been unable to adopt them. The Adobe apps were unable to transition to 64-bit until they moved their Mac UI code to Cocoa. InDesign only made the transition last year, at the same time that Adobe changed to a subscription pricing structure. Anyone who hasn’t upgraded due to the pricing change is still running a Carbon version of InDesign.

But even the Cocoa version of InDesign is not a great platform citizen. OS X reports that it always uses significant energy, even when idle. Its dialog boxes are just an NSWindow with an NSView. Adobe draws text and buttons in the NSView, and tracks mouse clicks in the view manually. Since there are no NSTextFields or NSButtons, these dialogs are completely invisible to screen readers.

This is in stark contrast to Lightroom, which was written with Cocoa in mind from the beginning. It’s still a cross-platform app, but all of its UI elements are subclasses of Cocoa classes. The app is accessible, and it doesn’t use significant energy while idle. More importantly, it can quickly adopt new features of the OS.

This is possible because Adobe wrote Lightroom’s interface entirely in Objective-C, and used Lua for the cross-platform logic. On Windows, Lightroom’s GUI is written using native frameworks. Both of these GUIs provide the same API to Lua, so there is extra work required to make sure that API changes are implemented identically on both platforms. The key difference is that InDesign writes as much cross-platform code as possible, only writing native code where it has to, whereas Lightroom writes as much native code as possible, only writing cross-platform code for platform-agnostic logic.

It took Adobe seven years after Apple announced the demise of 64-bit Carbon for InDesign to complete the transition. And now, just a year after the InDesign team completed their Cocoa rewrite, Apple has announced another transition in Swift. Swift doesn’t yet interoperate with C++, so Adobe can’t simply rewrite the Objective-C parts in Swift.

InDesign is not the only example of a Carbon app struggling to keep up with the platform. Its main competitor, QuarkXPress, also made the transition to Cocoa last year. Also like InDesign, QuarkXPress has a C++ API that developers can use to write third-party plugins. QuarkXPress’s API includes methods to add menu items to QuarkXPress’s menus. With the transition to Cocoa, this API ceased to work on the Mac, and was replaced with a native Cocoa API. The C++ Menu API still exists and works on Windows, creating a situation where a plugin can be written entirely in C++, with the single compromise that menu-adding code must be rewritten on OS X.

Smooth transitions, like the transition from Carbon to Cocoa, incentivize development plans that lead to such compromises, because they require periodic incremental improvements. Each of these improvements costs less than a full rewrite, but the combined cost of all these improvements outweighs the cost of a rewrite. In addition, each improvement costs more than the last, as each change Apple makes taxes the app’s original design further, and the previous incremental improvements each introduced further design constraints. At this point, it’s a such large task to just update these programs to work on modern platforms at all that they don’t work well and aren’t good platform citizens.

How Objective-C Could Become the Next Carbon

There are many features of Swift that make it a great language for Apple to write its future frameworks in. It probably won’t be long until some of these frameworks start to use Swift-only features like generics. Taking full advantage of platform improvements requires adopting new frameworks, and any Objective-C programs that wants to use these frameworks will need to write adapter code in Swift.

But Swift and Objective-C have different design philosophies. As time goes on, it will be harder to reconcile Objective-C’s design philosophy with native Swift frameworks. In order to simply get their apps to work, developers will spend a lot of time figuring out how to refactor their existing Objective-C codebases to fit within the constraints imposed by Swift, leaving them with less time for other improvements.

The future could also bring a new Swift runtime, one that’s incompatible with Objective-C. Apple took advantage of the 64-bit transition on the Mac to rewrite the Objective-C runtime. The 64-bit Mac runtime is the same as the iOS runtime. 32-bit Mac apps are left with the old runtime, and are thus unable to use some frameworks. A new Swift runtime could likewise cut off Objective-C apps from newer frameworks.

Any Objective-C app that gets as large and important as a Microsoft Office, Adobe Creative Suite, or Final Draft would be in the same position these apps are today. We’d still rely on them for day-to-day work, but they would become increasingly cumbersome to use, and increasingly expensive to maintain.

In contrast, a transition that breaks compatibility might be better for these apps in the long run. If Adobe had been forced to rewrite all their apps, it would have disrupted their development for a few years, but technology-wise, they would all be as well-off as Lightroom. Apple didn’t have the leverage to make such a transition back then, but they do now. Ten years down the line, we may look back and wish that Apple had told developers that Objective-C was going away, and that they needed to completely rewrite their apps in Swift.