Swift: Simple, Safe, Inflexible.

Aaron Brager
News on the Bloc
Published in
4 min readJan 7, 2015

Swift is Apple’s new succinct, powerful, and safe programming language for writing iOS and Mac apps.

Just like the safety from diesel nozzles, seat belts, and the need for two keys to open a safe deposit box, Swift’s safety comes at the expense of flexibility.

Two locks on a Sealed Authenticator System safeguard American missile launch controls. There is no single person who can unlock both locks.

Mattt Thompson alluded to this tradeoff in his NSHipster piece The Death of Cocoa. As part of the article, Mr. Thompson reviews several parts of the Swift language that are intuitive and expressive and shows how their application is bogged down by reliance on bridging to older Objective-C classes.

After reading Mr. Thompson’s article, a few students at Bloc (an online coding bootcamp) asked for clarification on the tradeoff between safety and flexibility. This article shows some examples in a bit more detail. It’s aimed at intermediate iOS / OS X developers, or advanced Objective-C developers who haven’t spent a lot of time with Swift.

Extending NSDate

As an example, let’s take a look at making NSDate a bit… Swiftier. Creating an NSDate is complicated, mostly because dates are complicated. NSDate is a class cluster, and an instance can be created by other objects like NSDateFormatter, NSCalendar, and NSDateComponents.

There’s still a primary use case, though, and we’d like it to be a lot easier in Swift:

In order to use our ideal syntax, Swift provides the StringLiteralConvertible protocol. Classes which conform to this protocol can implement init(stringLiteral value: StringLiteralType) which initializes an instance of this class using the string. (You also need to implement the two protocols this protocol inherits from — ExtendedGraphemeClusterLiteralConvertible and UnicodeScalarLiteralConvertible — more on that later.)

In Objective-C, to add methods to an existing class, you’d probably use a category. The equivalent in Swift is called an extension, and it’s described in the documentation like this:

Extensions add new functionality to an existing class, structure, or enumeration type.

So you might think you could simply declare conformance to this protocol, and provide implementations in an extension, like so:

But this won’t work, because of Swift’s safety rules. You’re stuck in between a rock and a hard place:

  • When you extend NSDate (or any class) with a protocol, you need to guarantee that all subclasses conform to the protocol. In order to do this, the initializer you’re adding has to be marked as required. Required initializers guarantee that every subclass implements or inherits that initializer.
  • Swift disallows required initializers from being declared in extensions.

The other option for extending a class’s functionality, of course, is subclassing. Here’s a subclass of NSDate, which conforms to StringLiteralConvertible:

This class has a singleton date formatter. In the initializer, the date formatter is used to convert the string to the time interval since NSDate’s absolute reference date. Then the interval is used to initialize the NSDate.

Running this code throws an exception:

Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘*** -[NSDate initWithTimeIntervalSinceReferenceDate:]: method only defined for abstract class. Define -[Dates.SwiftDate initWithTimeIntervalSinceReferenceDate:]!’

A closer look at the NSDate documentation indicates we’ve subclassed it incorrectly:

The major reason for subclassing NSDate is to create a class with convenience methods for working with a particular calendrical system. But you could also require a custom NSDate class for other reasons, such as to get a date and time value that provides a finer temporal granularity. If you want to subclass NSDate to obtain behavior different than that provided by the private or public subclasses, you must do these things:

[long list of things you don’t want to do]

Or in other, more cynical words: If you want to subclass NSDate, you must reimplement NSDate.

NSDate is complex to subclass because it’s a class cluster. And we can’t use an extension, as we saw above. So maybe we picked a bad example. Let’s try extending a simpler class: NSURL.

Extending NSURL

NSURL isn’t as complex as NSDate, but it’s a good candidate for literal convertibles, since it’s often initialized with strings:

We can’t implement StringLiteralConvertible using extensions for the same reason we couldn’t with NSDate. But NSURL isn’t a class cluster, so let’s try subclassing:

This subclass takes the string, value, and passes it to NSURL’s designated initializer init(string:relativetoURL:).

However, this code won’t compile. NSURL’s designated initializer is a failable initializer — it might return a URL, or it might return nil. But StringLiteralConvertible’s initializer is non-failable, and non-failable initializers cannot chain to failable initializers. This safety feature prevents non-failable initializers from failing, but it also prevents us from implementing StringLiteralConvertible on NSURL.

Suggestions

Here are a few ways Apple could improve Swift:

  • Allow developers to chain failable and non-failable initializers and handle possible failures themselves
  • Allow required initializers in extensions, and require subclasses to implement these initializers (even if they just call super)
  • Provide an option for developers to treat certain errors as silence-able warnings
  • Don’t use required initializers in literal convertible protocols
  • Make Swift open-source so developers can contribute to its development

I suspect many of these suggestions are being discussed, or in active development.

Summary

The example in this article — various difficulties implementing StringLiteralConvertible in Swift 1.1 — is just one type of problem you may see. Swift has many great features, among them an expressive and intuitive syntax. These features have built-in safety mechanisms that will improve the stability of iOS and Mac apps. But Swift’s feature set is far from complete, and the combination of incomplete features and aggressive safety measures make Swift less flexible than Objective-C.

The current inconveniences associated with strict safety may affect a developer’s choice of language for production apps. Those who want more flexibility may be discouraged from Swift, and stick to Objective-C. Those who value succinctness, speed, and safety will use Swift.

--

--

Aaron Brager
News on the Bloc

I have a secret plan to fight inflation. Also, I code iOS apps, try to understand ideas I disagree with, and sometimes play chess.