What would things be like if Swift had never been released?

This coming WWDC will mark the fourth anniversary of the introduction of Swift. I remember just how much that announcement hit me. I knew it was coming, but I most definitely wasn’t ready. I’ll be honest that I was in a bit of a daze for the rest of that day. This was such a fundamental change, it took me a while to process it.

A lot has changed since then. The language is now in it’s forth major release. It’s gone through multiple source-incompatible revisions. And, while Apple hasn’t yet shipped a Swift-first framework, it is now definitely just a question of when, not if.

But, “if” can be such a fun question :)

What If?

Imagine what the world be like if Apple hadn’t gone with a new language. What if, instead, Apple decided to iterate on Objective-C? I have no doubt that this was considered within Apple, because it’s the obvious route. The sheer volume of Objective-C code within Apple alone seems to justify working on the language, forget about 3rd-party code.

So, let’s take a look at a purely hypothetical take on what the path to an Objective-C 5.0 might have looked like. Along the way, I’m going to try to justify the motivation and technical feasibility by using work done for Swift. But, I’m not going to try that hard, so cut me some slack.

Objective-C 3.0

Objective-C 3.0 is really about preparation for future work. The primary goal is to introduce syntax that makes it easier to remove C constructs from existing code. Since this involves major work in the compiler, why not introduce some nice new language-level features too?

Phase out compatibility with C and C++: This is one of the major obstacles in memory safety and new syntax, so this has to go. Obj-C 2.0 will be the last version that will offer full support for either language, and 3.0 is now limited.

version that will offer full support for either language, and 3.0 is now limited. Dot method notation: While it never really bothered me, it’s clear the majority of developer don’t like the square-bracket syntax. This is made easier by dropping full support for C++.

“var” and “let” keywords: Another syntax construct many developers appreciate, this now makes it easier to control mutability. Perhaps Apple could even use these to blur the lines between NS* and NSMutable* classes.

@enum/@struct: Strongly-typed enums and value types are useful and a hugely popular part of Swift. Plus, Apple needs these to move way from C and macro usage.

nullability attributes and lightweight generics: These actually happened, and were awesome.

pattern-matching switch: This goes really nicely with @enum. Probably needs to be opt-in per-file.

@available: Personally, I’ve run into lots of problems adopting new Apple APIs while still supporting old OSes. What Swift has is great, and I want it in Objective-C too. (I’ve since been informed that I am an idiot, and @available was in fact introduced with Xcode 9. I guess you can tell how much Objective-C I’m writing lately…)

The Great Apple API Modernization, part 1: Remember that one of the main upsides for Apple here is to avoid rewriting entire frameworks, while still reaping the benefits of new language features. In this first phase, Apple has aggressively adopted these new features it its own APIs.

Objective-C 4.0

This is the version where things start to get really interesting. Paving the way with 3.0, Apple can now start to add large new features. It’s important to have an incentive for developers, because Apple’s also going to be making source-incompatible changes. With C compatibility in the rear-view mirror, lots of APIs need changing and that means developers have real work to do to adopt 4.0.

“Real Generics”, part 1: Let’s call this “medium-weight” generics. Moving towards a Swift-like type system, complete with the ABI challenges it brings with it. I’m guessing in-bundle dylibs will be needed as a temporary workaround, just like Swift.

Strict Initialization: Objective-C’s initialization system is super flexible, but allows for real abuse and bugs. Swift plugs these holes, and Apple will want that here too.

Access Control: Many people that design APIs appreciate this kind of control, but I’m sure none more than Apple itself. With Swift, Apple is much better able to prevent the kind of hacking that developers routinely do on their implementations. With better access controls (and probably ABI/Linker support), Apple can now actually enforce the boundaries they want.

Headers are now optional: This feature is worth it for the applause alone. But, practically speaking, now that C interoperability is in the past, there’s less of a need for headers in the first place.

“lazy var”, “get/set/didSet/willSet”: This are all examples of really handy features that move common Objective-C idioms into the syntax itself. I believe all of these will also have ABI implications.

@extension: This can be similar in functionality to Swift’s extension keyword. Nearly all the power of Categories, but no more global mutation of classes. Objective-C categories are powerful and weird, and their time has come. They are officially deprecated in this release.

The Great Apple API Modernization, part 2: Migrating what has to be tens of thousands of headers isn’t going to be easy. This just another step in what is sure to be a multi-year effort.

Aside from the normal API iteration, one major new feature is the removal of NSError from Obj-C 4.0 APIs. In it’s place is a Result type. Personally, I think the throw-try-catch paradigm introduced in Swift was a huge mistake. It’s too confusingly similar to exceptions, and not a great solution to the core problem. I’ve come around to using Result extensively, and I think it’s wonderful. Plus, this is my blog post, so I get to make the call.

Objective-C 5.0

Here’s where Apple gets to deliver some of the features and makes the changes they’ve been aiming for since the beginning. This language will, in a lot of ways, look like a hybrid between Swift and Objective-C. Importantly, it will require another ABI change, so libraries will still need to be shipped in the app bundle. This release more or less lines up with the current state of Swift 4.1.

Optionals: New syntax supporting optionals — after all, everyone loves ‘em! Of course, there are major runtime changes involved here.

No more object pointers: @class is a pointer and @struct is a value. Done and done.

No more messaging nil: Probably tied with square brackets as Objective-C’s most controversial feature, nil messaging is gone. You message nil, you crash. Goes hand in hand with optionals.

No more exceptions: I’m not a fan of exceptions. I like to think that the authors of Swift agree, because they’ve omitted real exceptions from the language completely. Since the ABI is in flux, now is the time to make drastic low-level changes like this.

No more ObjC Categories: @extension has now been here for a while, and it’s time to commit. Removing categories will require some complex source-level changes. And, it will have major functionality implications for code, especially code that monkey-patches Apple classes. But, Apple hates it when you do that, so tough luck.

“Real Generics”, part 2: Apple continues to fill out the type system and generic support. @extension and @protocol can now be constrained. All of this follows along just like it did with Swift.

The Great Apple API Modernization, part 3: I’m just leaving this in as an on-going effort. Perhaps this is the time to drop the NS prefix. Seems like as good a time as any, now that all the *s are going away.

Easy, Right?

Consider how much work Apple must have put in to bridge Objective-C to/from Swift. Add to that how much work developers have done to adopt Swift (and 2.0, and 3.0, and 4.0). Avoiding as much of this as possible seems compelling. I think the total technical work outlined above is roughly in line with what’s actually been done for Swift. But, the disruption to Objective-C code bases has been drastically reduced. That’s a significant win.

But, should Apple have done this? I think it’s hard to say. One of the great things about a new language is the chance to establish a new culture. Given the public proposals, the Swift blog, the open source code, multi-platform support, I’d say they have achieved that in spades. The post-Swift Apple is almost unrecognizable from the pre-Swift Apple. I’m not sure even the decision-makers that gave Swift the green light could have guessed what a profound effect it would have on the company. Just how much of that was due to the clean language break is up for debate.

I can also imagine people more familiar with runtime and ABI implementations rolling their eyes at this post. Yeah, it’s just that easy right? I know, I’m grossly oversimplified many things and probably suggested more than one thing that is technically impossible. It’s all just for fun, though, so I don’t feel too bad.

One thing is for sure, now I want to check out this Obj-C 5.0.

Update: Clearly, I didn’t do a good enough job of explaining my goal here. What I was trying to do was take Swift’s feature set as an end point, and get there with a different path. This was based on the assumption that this feature set Apple wanted one way or the other. The only reason I imagined Apple would abandon source-level compatibility with C and C++ is because they actually did that with Swift.

So, for the record:

- I enjoy nil-messaging, but acknowledge that it trips up many people

- I think Obj-C as a superset of C was brilliant and largely the reason for its phenomenal success

- I think Obj-C++ is also awesome, though sometimes used when pure Obj-C would be a better fit

- I now write Swift (almost) exclusively and I really like it

But, I guess I have to close out with what I might have done, had it actually been up to me. I wouldn’t have built a new language, especially at the time. There’s just too much existing code that could benefit from iteration on Objective-C. Beyond that, I’m unsure. Some of the ideas above interest me, but I’d need way more time to think about it.