Swift: From an Android Developer's perspective


At Zuno, I'm the resident Android developer, but being close to the only one in the office that doesn't use an iOS device daily made me wonder what the other side was like. So, I decided to play with Apple's new programming language, Swift.

(note: since Swift is a new and developing language, I can't guarantee what I write will be accurate when it's production ready)

OS X and iOS apps are primarily written in Objective-C and that's because of the operating system's heritage with NextStep. This is why all the core classes start with NS. Now, Objective-C does solve problems. Back when it was created in 1983, it provided a method to describe problems in an object oriented way. However, I don't think the syntax has aged very well. Take the following for example:

// Objective-C
[obj method:argument];

compare to

// C++

This is the reason why Swift was conceived. As Apple puts it, it's "Objective-C without the C." Here are some things that caught my eye.

Type System

Swift does have safe typing (which is great) but it doesn't make you explcitly declare the types of your variables. It'll assume the types of a variable when it's declared and assigned a value. These are valid assignments in Swift:

var a:Int = 2; // a is of type Int
var b     = 3; // b is also type Int

The same assumptions apply in functions:

func increment(x:Int) { return x + 1; }
func increment(x:Int) -> Int { return x + 1; }  

Here, increment has a type (Int -> Int) a function that takes an Int and returns an Int. Those familiar with Haskell will recognize the arrow notation. It's really useful for getting lots of information about a function at a glance.

The Optional Type

This is one of those concepts that appear useless, but when put into practice it helps immensely. Optional<T> is a type where the value can be anything in T or nil. In other words, the value is optional.

Here's an everyday example: say that we're fetching data from a server. As we all know, things can go wrong when we do this (for example, the network goes down or something happens to the server).

Let's assume we have something like this:

var remoteData:JSON = getData();

We have no way of knowing that getData will succeed so if it blows up we can have a runtime error. We'd have to catch the exception or hope for the best.

In Swift, we can do this:

var remoteData:JSON? = getData();

if let data = remoteData {
} else {

The type JSON? is the same as Optional<JSON>. We know from the first line that getData returns a JSON object or nil. Below, we check to see if remoteData is nil and assign it to data. The important thing is since data is of type JSON? we have to add an ? at the end of it in order to call any methods on it.

Java developers might say that a method that throws a NullPointerException is equivelant, however, since the information is in the type, it can be enforced by the compiler.

A function that returns T is guaranteed, where as T? can be nil. Or to put it another way, a funciton that has an argument of type T can only operate on T; the operand must not be nil.

First-class functions and closures

Functions are first class in Swift. This is good, because it let's us do things like map and reduce on collections and have callbacks that don't feel like a total hack (i.e Java's Runnable).

Here's the how you would define a closure:

{ (x:Int) -> Int in x + 1; }

(Do note, the usage of in)

And of course, we can treat it like a value.

var inc:(Int -> Int) =  { (x:Int) -> Int in x + 1; }

The obligatory map example:

map([1,2,3], {(x) in x + 1});

Oddly enough, map is a method of lists.

[1,2,3].map({ (x:Int) -> Int in x + 1; })

You can of course define your own functions that operate on other functions. Let's define a function double that returns a function composed with itself, i.e f . f.

func double ( f:(Int -> Int) ) -> ( Int -> Int ) {
    return { (n) in f(f(n)) };

Even though next version of Java does have lambda expressions, the fact that I can't in Android development now makes me look on Swift with envy.