Why Swift?

June 9, 2014

3 comments

From the moment Apple has announced Swift, the new iOS and OS X programming language, the web is full of hate and praise, constructive criticism and pointless rants, confusion and excitement — and many of these boil down to “why Swift?” — namely, why Apple chose to design a new programming language rather than pick and adapt an existing one.

Needless to say, I don’t work for Apple, so all I can offer is an educated guess based on a lot of playing with Swift and trying to understand the mindset that led to its design and implementation. If you have your own opinion, I’d love to hear it in the comments or — even better — in your own blog post.

Swift Design Goals

When you see a new programming language, you must ask what its design goals have been. Swift is designed to replace Objective-C, but that’s not a goal in and of itself. There are many flaws with Objective-C and many ways to “fix” them, so we must be more specific. Also, saying Swift is a more modern language is not enough. We need to point out how it is more modern and what we get out of it. So, here’s my attempt at the design goals of Swift:

1. Performance and Runtime

Swift must compile down to native code with no runtime compilation or interpretation. Swift must be able to match and exceed the performance of optimized Objective-C code without requiring an expensive runtime or a full-blown garbage collector. The reason for the latter requirement is that Swift must compete in the iOS world, where devices are memory-restricted and cannot afford garbage collection or costly runtime services. The security architecture of these devices also precludes — or at least makes undesirable — just-in-time compilation.

2. Interop with Objective-C

Swift must make it trivial to interact with existing Objective-C code. This means it must be easy for Swift code to call Objective-C code, and it must be possible (and ideally easy as well) for Objective-C code to call Swift code. The interop should not just be on the module level — it should be possible for a Swift class to implement an Objective-C protocol, or for a Swift class to extend an Objective-C class through either an extension or inheritance.

3. Type Safety

Ten years of Objective-C in the mainstream must have proven that its dynamic, loosely-typed nature isn’t a great idea for the robustness users tend to expect from mobile apps. (Hey, don’t crucify me over this last statement; while it is possible to write robust code in a non-type-safe language, I personally believe it is easier to do so in a type-safe language.) It’s also not very good for performance: Objective-C method calls are always bound at runtime and go through a messaging infrastructure that precludes compiler optimizations such as inlining and makes it very difficult to perform whole-program optimization.

For example, I never saw a good reason for putting objects of multiple types into the same NSArray or NSDictionary. But hey, the language allows us, so you tend to drift with the wind. I also saw no reason for delegate hosts to use @optional methods and canPerformSelector: instead of requiring the delegate to implement whatever methods are required, but with this design forced on you at every opportunity (with the simplest examples being UITableViewDataSource and UITableViewDelegate), you end up adopting it as well.

Swift, then, must be type-safe. Collections of “any object” and properties “of any type” should be the exception, not the rule. There must be facilities for strongly-typed generic code and for compile-time safety of variable assignments.

4. Better Nil Handling

If you ever programmed in Objective-C, you know it has a weird way about nil handling. When you call a method on a nil pointer, it just silently does nothing and returns nil (or 0, or NO — depending on what your method is supposed to return). Although there are some situations where you can actually take advantage of this, at some point it will bite you.

Swift must do better where nil handling is concerned. There should be a clear way to express that a variable cannot be nil, and the compiler should be able to verify it. When variables can be nil, they must be explicitly tested for nil before they can be used — and again the compiler should be able to verify it.

5. Unification and Modernization of Function Types

Function types in Swift must be first-class citizens. It should be possible — and easy! — to pass functions to other functions, to return functions from other functions, and to create closures with a simple syntax and intuitive behavior.

Objective-C, by the way, comes pretty close with its blocks syntax, but it has a few setbacks: first, you must mark mutable closed variables explicitly (with the __block keyword); second, the way to avoid reference cycles between an object that references a block and the block itself is pretty ugly; third, blocks are not equivalent to function pointers and cannot be used interchangeably with function pointers.

6. Memory Management and Memory Safety

Swift must make memory management automatic and safe. Developers should not have to explicitly delete memory that they allocated, and should have to write explicit deinit methods infrequently. Swift must also make it very hard (if not impossible) to perform unsafe memory accesses, such as pointer arithmetic and unsafe pointer casts (such as integer to pointer conversion).

Again, Objective-C with ARC (Automatic Reference Counting) goes a long way in terms of memory management, but is still full of potential holes for unsafe memory accesses.

7. Easy Transition Path from Objective-C

Swift should make Objective-C developers feel at home, at least around the fundamental concepts such as: the type system, classes, inheritance, initialization, protocols, and other language features. It should do so without compromising on the other design goals whenever possible.

8. Miscellaneous

There are of course additional design goals that I am not listing here, which are implicit in the language as we see it today. The strong pattern-matching capability on enums and other types is one of my favorite Swift features, and is clearly “borrowed” from modern functional languages. Operator overloading and custom operators is another example. But I consider these to be mostly convenience features, and not a pillar of the language, despite their usefulness.

Defining custom operators in Swift can be fun.

Defining custom operators in Swift can be fun.

So, What’s Wrong With XYZ?

With that said, why not simply use an existing programming language? Setting aside any potential concerns about copyrights,  Apple could pick any existing programming language and perform minimal adaptation to make it suitable for use with iOS and OS X. The potential benefits would include 1) tapping into an existing developer community, 2) not spending as much time working on the language design and syntax, 3) possibly allowing existing code reuse from the developer community, 4) making it easier to develop cross-platform applications that run on iOS and other platforms.

But when you try to come up with an actual mainstream language that would be suitable for this, the design goals we discussed above might have some strong objections.

C++

For example, consider C++. A mainstream language, no doubt, with existing cross-platform support for iOS, Android, Windows Phone, Windows, OS X, Linux, microwaves, electric bicycles, and whatnot. Apple’s compiler toolchain even supports C++ today — you can go ahead and use it on OS X or iOS. My biggest objections to C++ today are memory safety and the unprecedented complexity of the language. Even though it’s possible to be productive in modern C++, the opportunities for getting something wrong are so common that I would hate to see C++ as the standard for iOS and OS X development.

Java

Next, consider Java. I’ll even be willing to forgive its verbosity and sometimes-plain-ugliness, but can it be married with the design goals above? I think not. Compiling Java down to native code with no garbage collection and no costly runtime means getting rid of a very large part of the language and its runtime features, producing a dialect that will be largely incompatible with any existing Java code (and thus missing the goal of using an existing language). Additionally, adapting Java to make it compatible with existing Objective-C code would require introducing several non-trivial language extensions to support categories, function types, protocols (which are not quite the same as interfaces), and custom value types. Again, it wouldn’t quite be Java after it’s been steamrolled by Objective-C. Any potential for existing code reuse, cross-platform compability, and tapping into an existing developer community would be lost if the language undergoes significant adaptation.

C#

Finally, how about C#? Xamarin has been very successful compiling C# down to native code and running with a minimal runtime layer on iOS — although still with garbage collection services. Xamarin have also set a standard for adapting Objective-C language features to C# — exposing protocols as interfaces, action methods as event handlers, and so on. C# still doesn’t fully deliver on some of the design goals above (such as a stronger stance on nil handling and pattern matching), but perhaps that could have been baked into the language with certain perturbations.

But in case you haven’t noticed, Apple has a very strong stance against full garbage collection on mobile devices (and perhaps rightly so). It might be worth the thought experiment to work on removing garbage collection support from C# and replacing it with reference counting. There is no fundamental problem with that, except for the additional language support that would be required for conveniently expressing weak/non-owning references. The result of these adaptations would again be a dialect of C#, incompatible with the “mainstream C#” we know today.

How many iOS developers actually speak C#, however? Would it really be easier for them to transition from Objective-C to C# than to Swift? Would introducing a different dialect of C# that would be incompatible with “mainstream C#” be easier for existing C# developers than forcing them to learn a new language? These are interesting questions. I personally prefer a new language with an almost-clear slate to an incompatible dialect of another language. With both Microsoft and Apple pulling C# in two different directions, the end result could be — effectively — two different languages, anyway.

Summary

I realize many of the points above are controversial, and as I said in the very beginning, all I’m offering here is my opinion. I know one thing for sure after having used Swift for less than a week, and it’s that I unequivocally prefer it to Objective-C (and that’s from a developer who got used to Objective-C’s quirks very quickly!). If Swift’s net effect is that iOS and OS X developers can be more productive in a language that’s type-safe, memory-safe, and interoperable with existing APIs, then I’m pretty happy even if it’s not a language that I knew a week ago.


I am posting short links and updates on Twitter as well as on this blog. You can follow me: @goldshtn

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

3 comments

  1. Pingback: In the News: 2014-06-09 | Klaus' Korner

  2. Paul ToppingJune 12, 2014 ב 11:58 PM

    You may have missed something that Microsoft has been doing for a year or so. They now have defined the Windows API in some kind of IDL from which they can generate libraries and headers for a variety of programming languages with the promise that one could add more simply by defining a code generation module. This scheme allows programmers to write to Windows API in all those languages as if the APIs were native in their language. No need to write C++ class wrappers on top of C-callable APIs. No need to figure out how to called DLLs (shared libs to others) from your favorite programming languages. It even takes care of translation of argument and return types. Too bad Apple didn’t do something like this.

    Reply
    1. Sasha Goldshtein
      Sasha GoldshteinJuly 6, 2014 ב 9:44 AM

      Paul, this is not entirely accurate. First of all, Microsoft has only wrapped Modern APIs with WinRT metadata. Definitely not the entire Win32 API surface. Second, “one could add more simply by defining a code generation module” is easier said than done. If you look at the actual JavaScript language projection layer, for example, you’ll see that it has to take care of a LOT of detail. It’s very hard for someone outside of Microsoft to use WinRT metadata in a transparent fashion — unless they can already do interop with COM, which is not new. Plus, “even takes care of translation of argument and return types”, a.k.a. marshaling, works well only in simple cases. When you need to marshal complex types, or think of memory management (allocated on one side, freed on the other side) you still have to invest a lot in the marshaling layer and understand it thoroughly. In other words, don’t believe everything the pundits say :-)

      Reply