Swift 2 - Introduction and Comparison
Swift is a new programming language created by Apple with a couple of interesting programming paradigms and differences to the big established languages. Like Objective-C Swift is created for iOS, OS X and watchOS development und should be a safer, faster and more powerful alternative to Objective-C.
Source: StackOverflow: http://stackoverflow.com/research/developer-survey-2015
Like shown in the survey 2015 from StackOverflow Swift has already gained great popularity.
Overview
Swift is a multi-paradigm language which follows object oriented (Java, C#), functional (Haskell, Standard ML), imperative (C, C , Objective-C) paradigms and elements from script languages (Python, Scala). Chris Lattner, the creator of the language, himself says “from Objective-C, Rust, Haskell, Ruby, Python, C#, CLU, and far too many others to list.”[1] It offers inheritance, type inference, generic programming, closure, multiple return values, etc. In this post we will have a look at the most interesting differences and features.
Performance
According to the presentation of Swift 2.0 at the WWDC 2015 (annual Apple Worldwide Developer conference) Swift is supposed to be a lot faster than Objective-C:
Source: Apple: https://developer.apple.com/videos/wwdc/2015/?id=409
This results out of more and better compiler optimizations.
Source: Primate Labs: http://www.primatelabs.com/blog/2015/02/swift-performance-updated/
Let’s compare Swift to C . According to the benchmarks from Primate Labs Swift has approximately the same average performance as C except in the GEMM test, where C is still about 4.5 times faster.
Note: This test was made with Xcode 6.1.1 Beta 3. The latest version right now is Xcode 7 Beta 4 (Aug. 2015).
Getting Started:
To get started, visit this website https://developer.apple.com/swift/resources/. From there you get a lot of code samples, projects and tutorials. Additionally you can read all “The Swift Programming Language *” books for free, which are complete guides through the language.
Hello, world!
Let’s follow the tradition and have a look at the “Hello World” program:
Swift:
1 |
print("Hello, world!") |
Java:
1 2 3 4 5 6 7 |
public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, world!"); } } |
Objective-C:
1 2 3 4 5 6 7 8 |
int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"Hello, World!"); } return 0; } |
As you can obviously see, it’s a lot more code in Java and Objective-C than in Swift. This single line in Swift tells us a lot: Swift doesn’t need a main function and semicolons at the end of expressions and works also like a script language. If we only want to do something simple like this print statement, languages like Java produce an overhead, because we are forced to create a class. By the way, print is a global function in Swift and fortunately we don’t need the @-notation for strings anymore.
Type inference
Swift
1 2 3 4 5 6 7 |
let e: Int = 3 var a = 5.678; // implicit Double // a = a + e a = a + Double(e) print("\(e) \(a)") |
Java
1 2 3 4 5 6 7 8 9 10 11 12 |
public class HelloWorld { public static void main(String[] args) { final int e = 3; double a = 5.678; a = a + e; System.out.println(e + " " + a); } } |
Objective-C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//#import <Foundation/Foundation.h> // works without importing but the compiler warns us with "Implicitly declaring library function 'NSLog' with type 'void (id, ...)'" int main(int argc, const char * argv[]) { const int e = 3; double a = 5.678; a = a + e; // e + " " + a; NSLog(@"%d %f", e, a); return 0; } |
Whereas we always have to declare the type of variables in Java or Objective-C, we don’t have to in Swift. The compiler calculates the type through type inference. Like in the example ‘a’ is implicit of type Double. Without the Int keyword, ‘e’ would have been implicit of type Int, because we assign ‘e’ with an Int value.
The equivalent of ‘final’ in Java or ‘const’ in Objective-C is ‘let’ in Swift. IMHO[2] ‘fin’ or ‘con’ would have been more intuitive.
Furthermore we always have to cast the types in Swift. The marked line would cause a compiler error, because ‘e’ is not of type ‘Int’. Whereas we can use in Java and Objective-C the implicit cast.
Multiple return values and tuples
Swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
func calculateMinMaxSum(a: Int, b: Int) -> (min: Int, max: Int, sum: Int) { if a > b { return (b, a, a + b) } else { return (a, b, a + b) } } let statistics = calculateMinMaxSum(5, b: 19) let (min2, max2, sum2) = calculateMinMaxSum(5, b: 19) print(sum2) // prints 24 print(statistics.sum) // prints 24 print(statistics.2) // prints 24 |
Standard ML
1 2 3 4 5 6 7 8 9 10 11 |
load "Int"; fun calculateMinMaxSum(a:int, b:int):int*int*int = if a > b then (b, a, a + b) else (a, b, a + b); val statistics = calculateMinMaxSum(5, 19); val (min, max, sum) = calculateMinMaxSum(5, 19); print(Int.toString(#3 statistics)); (* Tuples begin in SML at 1 *) print(Int.toString(sum)); |
There are no real equivalents to tuples or multiple return values in Java, Objective-C or JavaScript, but Standard ML supports all of these elements and IMHO you can see, that Swift has a lot in common with SML. You would have to return an extra type or array in Java or Objective-C, but often you would cause an overhead to create an extra class for these few properties and in an array the elements must be of the same type. You could also return a tuple in Swift or SML of complete different types (sugar: Double, milk: Int, others: String).
SML supports an even more complete type inference, so that we can rewrite the procedure ‘calculateMinMaxSum’:
1 2 3 4 |
fun calculateMinMaxSum(a, b) = if a > b then (b, a, a + b) else (a, b, a + b); |
without any explicit named types and the type of the procedure still is: val calculateMinMaxSum = fn : int * int -> int * int * int. The reason Swift doesn’t go that far has probably something to do with features like subtyping and overloading, which doesn’t exist in SML and makes it really hard for the language design, compiler and the awareness of the developer.
Maybe you recognized that in the Swift example the second parameter in the ‘calculateMinMaxSum’ call was labeled with ‘b’ like the parameter in the function and the first parameter isn’t labeled. That’s because you have to label all parameters after the first one like in the function and the compiler even returns an error if you label the first parameter. This is an interesting syntax and can make the developer aware of the function’s parameters, but also leads to more code and IDEs could help at this point out.
Strings:
Swift
1 2 3 4 5 6 7 |
let dogLabel = "?" let catLabel = "?" let dogCount = 1 let catCount = 3 let wholeStr = "Hello, I have " + String(dogCount) + " " + dogLabel + " and \(catCount) " + catLabel + "s"; print(wholeStr) // Hello, I have 1 ? and 3 ?s |
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class HelloWorld { public static void main(String[] args) { final String dogLabel = "\uD83D\uDE38"; final String catLabel = "\uD83D\uDC36"; final int dogCount = 1; final int catCount = 3; // usual approach final String wholeStr = "Hello, I have " + dogCount + " " + dogLabel + " and " + catCount + " " + catLabel + "s"; // using string interpolation // produces the same result final String wholeStrInterpol = "Hello, I have " + dogCount + " " + dogLabel + " and " + String.format("%d", catCount) + " " + catLabel + "s"; System.out.println(wholeStr); } } |
Objective-C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { const NSString* dogLabel = @"\U0001F436"; const NSString* catLabel = @"\U0001F638"; const int dogCount = 1; const int catCount = 3; // ugly approach const NSString* wholeStr = [[[[@"Hello, I have " stringByAppendingFormat:@"%d ", dogCount] stringByAppendingString:dogLabel] stringByAppendingFormat:@" and %d", catCount] stringByAppendingFormat:@" %@s", catLabel]; // more elegant approach const NSString* wholeStrInterpol = [NSString stringWithFormat:@"Hello, I have %d %@ and %d %@s\n", dogCount, dogLabel, catCount, catLabel]; NSLog(@"%@\n", wholeStr); } return 0; } |
One amazing new feature is, that Swift has a full Unicode support. Like shown in the example above you can directly declare the value “DOG FACE” from the Unicode set. In contrast to Java or Objective-C, where we have to to use the Unicode identifier. On top of that you could declare a variable named liked the dog smiley “let ???? = 5″. This is a big advantage for developer who have to handle a lot with non-usual Unicode characters and exotic languages. It can also lead to illegible code for non-native speakers, if someone doesn’t pay attention to the international standards.
Usual operations like string concatenation was annoying in Objective-C, if you are used to a ‘ ’ operator for Strings. The more elegant approach in Objective-C was to use the stringWithFormat function, using string interpolation, but it isn’t really equivalent to the Swift example. We used in the Swift example the string concatenation operator ‘ ’ and string interpolation. So the ugly approach from the Objective-C example is more equivalent to the ‘ ’ operator and you can see how messy it is.
At this point you can also recognize that Swift uses the dot notation like in Java and not the SmallTalk like syntax.
Class, Structs and Protocols
Swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
// Class class SomeClass { var favLang: String init(favLang: String) { self.favLang = favLang } } let aClass = SomeClass(favLang: "Assembler") let bClass = aClass bClass.favLang = "Swift" print(aClass.favLang) // "Swift" print(bClass.favLang) // "Swift" // Struct struct SomeStruct { var favLang: String init(favLang: String) { self.favLang = favLang } } let aStruct = SomeStruct(favLang: "Assembler") let bStruct = aStruct bStruct.favLang = "Swift" print(aStruct.favLang) // "Assembler" print(bStruct.favLang) // "Swift" |
Java
1 2 3 4 5 6 7 8 9 |
public class SomeClass { public String favLang; public SomeClass(String favLang) { this.favLang = favLang; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class Program { public static void main(String[] args) { final SomeClass aClass = new SomeClass("Assembler"); final SomeClass bClass = aClass; aClass.favLang = "Swift"; System.out.println(aClass.favLang); // "Swift" System.out.println(bClass.favLang); // "Swift" } } |
Objective-C
1 2 3 4 5 6 7 8 9 10 11 12 |
#ifndef SomeClass_h #define SomeClass_h @interface SomeClass : NSObject @property NSString *favLang; - (id)init:(NSString *)comeClass; @end #endif /* SomeClass_h */ |
1 2 3 4 5 6 7 8 9 10 11 12 |
#import <Foundation/Foundation.h> #import "SomeClass.h" @implementation SomeClass -(id) init:(NSString*)favLang { self.favLang = favLang; return self; } @end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#import <Foundation/Foundation.h> #import "SomeClass.h" int main(int argc, const char * argv[]) { @autoreleasepool { const SomeClass *aClass = [[SomeClass alloc] init:@"Assembler"]; const SomeClass *bClass = aClass; aClass.favLang = @"Swift"; NSLog(@"%@\n", aClass.favLang); // "Swift" NSLog(@"%@\n", bClass.favLang); // "Swift" } return 0; } |
Let’s have a look at the cornerstone of the OOP world. Swift has the concept of classes and structs. The classes are equivalent to Java’s classes or Objective-C’s interfaces. The behavior is all the same in Swift, Java and Objective-C. We create an object ‘aClass’ while ‘bClass’ and references ‘aClass’. Afterwards we change ‘favLang’ to “Swift”. ‘aClass’ and ‘bClass’ just show to the same point in the memory. Thus classes are reference types.
Structs in Swift act different to classes and structs from Objective-C/ C/ C .
Structures support many of the same behaviors as classes, including methods and initializers. One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference. [3]
The Swift struct’s example prints at first “Assembler” and then “Swift”, because ‘bStruct’ doesn’t hold a pointer to the same memory address, all values are copied and with the statement “aClass.favLang = “Swift”” only the value of ‘aStruct’ changes. Consequently structs are value types.
There are some big differences between these three languages as we can see in the examples. Swift:
- doesn’t use header files (like Java)
- supports structs but act as value types
- has a constructor called ‘init’ (Objective-C doesn’t have constructors)
- forces the developer to name parameters in a constructor call (Line 30). IMHO that seems inconsistent to me, because Swift forces the developer not to label the first parameter in a method call.
Swift also supports inheritance and protocols aka. interfaces.
Functions and Closures
Swift
1 2 3 4 5 6 7 8 |
func makeIncrementer() -> (Int -> Int) { func addOne(number: Int) -> Int { return 1 + number } return addOne } var increment = makeIncrementer() increment(7) // returns 8 |
Standard ML
1 2 3 4 5 6 7 8 9 |
fun makeIncrementer():int->int = let fun addOne(number: int):int = number + 1; in addOne end val increment = makeIncrementer(); increment(7); // returns 8 |
Welcome to the functional world! And again Swift and Standard ML look pretty similar. The variable ‘increment’ itself is a function, because ‘makeIncrementer’ returns the inner function ‘addOne’ of type ‘int -> int’. It takes an argument of type int and returns an argument of type int. This concept ist called closure. It doesn’t exist in Objective-C and is only available in Java since version 8:
1 2 3 4 5 6 7 8 |
public static UnaryOperator<Integer> makeIncrementer() { return (i) -> 1 + i; } public static void main(String[] args) { UnaryOperator<Integer> increment = makeIncrementer(); System.out.println(increment.apply(7)); // prints 8 } |
Switches and Patterns
Swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
let somePoint = (1, 1) switch somePoint { case (0, 0): print("origin") case (let x, 0): print("I can do sth with the x") case (-2...2, -2..<6): print("inside the box") case let (x, y) where x == -y % 3: print("some calculations") default: print("nirvana") } // prints "inside the box" |
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
public class PointProgram { private static class Point { public final int x; public final int y; Point(int x, int y) { this.x = x; this.y = y; } } public static void main(String[] args) { Point p = new Point(1, 1); //The tuple '(1, 1)' from the Swift example was realized with a private class if (p.x == 0 && p.y == 0) System.out.println("origin"); else if (p.y == 0) { final int y = p.y; System.out.println("I can do sth with the x"); } else if (p.x >= -2 && p.x <= 2 && p.y >= -2 && p.y < 6) System.out.println("inside the box"); else if (p.x == -p.y % 3) { System.out.println("some calculations"); } else { System.out.println("nirvana"); } } } |
How sweet the syntactic sugar is! Swift’s switch supports tuples and on top of that we can create pattern to match the right properties. ‘let x’ is a wildcard and puts the value in the constant ‘x’, whereas in Java we need an extra line for the assignment (line 21). The range operators ‘…’ (includes both values) and ‘..<‘ (omits its upper value) makes the code clear and easy to understand, whereas in Java we need 4 checks. Even in the switch statement we can check for further properties with ‘where’. These kind of checks are not possible in neither in Java nor in Objective-C. This is even true if we would check on a single Integer in a switch statement. We couldn’t easily write “case x == 5 % x:”
The pattern matching and the range operators are great new features, which improves the tidiness and understanding in the code.
Note: There is no real tuple equivalent in Java, but to demonstrate the clarity in the Swift’s example, the tuple was realized with a private class.
Optional Values
The concept of optionals doesn’t exist in C or Objective-C. The nearest thing in Objective-C is the ability to return nil from a method that would otherwise return an object, with nil meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structures, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound) to indicate the absence of a value. This approach assumes that the method’s caller knows there is a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants. [4]
Swift – Optional#1
1 2 3 4 5 6 7 |
let possibleNumber:String = "123" let convertedNumber = Int(possibleNumber) // returns an optional value if convertedNumber != nil { print("convertedNumber value: \(convertedNumber)") // "convertedNumber value: Optional(123)" print("convertedNumber value: \(convertedNumber!)") // "convertedNumber has an integer value of 123" } |
Optional values are a profound concept in Swift, therefore we will take a detailed look. Here we go:
The Int() initializer returns an optional value, because it is not guaranteed that the passed parameter is correct. The != and == operators are overloaded and implicitly compare the unwrapped value of ‘convertedNumber’. To the contrary to Java or Objective-C even primitive datatypes can have the value ‘nil’. Hence ‘possibleNumber’ was a legitimate argument, ‘convertedNumber’ is not nil. The prints are above. The exclamation mark unwraps the value. That’s the reason why the output is:
convertedNumber value: Optional(123)
convertedNumber value: 123 (Without “Optional” because the !-operator unwrapped the variable)
Swift – Optional#2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
let possibleNumber:String = 123 let a:Int? = 5 // optional variable let b:Int = 6 // normal variable let c:Int! = 7 // implicitly unwrapped optional print(a) // "Optional(5)" print(b) // "6" print(c) // "7" let d:Int? = Int(possibleNumber) let e:Int = Int(possibleNumber)! let f:Int! = Int(possibleNumber) print(d) // "Optional(123)" print(e) // "123" print(f) // "123" print(d!) // "123" // print(e!) // not allowed print(f!) // "123" |
The variables a, b, c, d and f show us the three options: optional variables (‘?’), normal variables and implicitly unwrapped optional variables (‘!’). The first print prints similar to the example before “Optional(value)” because the variable is optional and not unwrapped. ‘c’ acts like a optional value and we can pass optional values (like we do with ‘f’), but the value is always implicitly unwrapped. ‘e’ is a normal value, therefore we cannot pass an optional value and have to unwrap ‘Int(possibleNumber)’ with an exclamation mark. That’s also the reason why we are not allowed to unwrap ‘e’ (line 18). We can unwrap ‘f’ but it has no effect and the print would have been the same without exclamation mark.
Swift – Optional#3
1 2 3 4 5 |
let noNumber = "?" let g:Int! = Int(noNumber) print(g) // "nil" print(g!) // fatal error: unexpectedly found nil while unwrapping an Optional value |
Now, it’s getting interesting. ‘g’ is an implicitly unwrapped optional value. ‘Int(noNumber)’ returns ‘Optional(nil)’ because the baby chicken is unfortunately not a proper number. ‘g’ implicitly unwraps the value and ‘nil’ is first printed. The next line causes an error because we try to unwrap a value which was never set.
Now an example, where optionals are a great advantage:
Swift
1 |
winSize = house?.windows?.get(2)?.size |
Java
1 2 3 4 5 6 7 8 9 10 11 12 |
if (house != null) { windows = house.windows; if (windows != null) { win = windows.get(2); if (win != null) winSize = win.size; } } |
This problem is called Pyramid of doom and leads in many languages to confusing code. Optional chaining in Swift solves this problem in one line and looks quite elegant.
Let’s face the other side of the coin:
1 2 3 4 5 6 7 8 9 |
let optval : Bool? = false // if optval { print("0") } // Optional type 'Bool?' cannot be used as a boolean; test for '!= nil' instead if optval != nil { print("1") } if optval! { print("2") } if optval == false { print("3") } if optval! == false { print("4") } if optval == true { print("5") } if optval! == true { print("6") } if !optval! == true { print("7") } |
What’s the output? It’s not that easy:
1 2 3 4 |
1 3 4 7 |
The upper example shows that optional values make code very complex. “3” and “4” are printed because “==” and “!=” are overloaded and unwrap the optional implicitly. Additionally the negating exclamation mark in combination with the unwrapping operator leads to confusing code.
For the sake of completeness it has to be added that since version 8 Optionals also exist in Java, but there are not really anchored and common yet. Also StandardML supports Optionals.
IMHO: Are optional values blessing or curse in Swift? Personally I think that optional values make the code too complex and distract from the actual logic. I don’t see a big advantage to hazard the disadvantages. Optional chaining (Swift) without optionals like in C#’s null propagation would have been the best compromise.
Conclusion
Swift brings some great features like simple String operations, full Unicode support, functional elements combined with object oriented elements, tuples and extended pattern matching. I’m glad that Swift uses the dot notation instead the SmallTalk syntax like in Objective-C. Compared to Objective-C the code appeals cleaner. It seems that Apple wanted to establish a beginner friendly programming language. I don’t feel convinced of the optional value concept, but I’m curious to see how the concept will hold up in larger projects in the future. Also allowing the developer to omit the type can increase the potential of error. What’s your impression? Leave a comment what your opinion is!
Sources:
[1] http://nondot.org/sabre/
[2] IMHO = In My Humble Opinion
[3] Apple: The Swift Programming Language (Swift 2 Prerelease) Page 31
[4] Apple: The Swift Programming Language (Swift 2 Prerelease) Page 73
Update 6th Oct. 2015: Added a Java closure example and complemented the Optionals part.
Recent posts






Comment article