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

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.

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:

Swift

1

print("Hello, world!")

Java:

Java

1

2

3

4

5

6

7

publicclassHelloWorld{

publicstaticvoidmain(String[]args){

System.out.println("Hello, world!");

}

}

Objective-C:

Objective-C

1

2

3

4

5

6

7

8

intmain(intargc,constchar*argv[]){

@autoreleasepool{

NSLog(@"Hello, World!");

}

return0;

}

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

Swift

1

2

3

4

5

6

7

lete:Int=3

vara=5.678;// implicit Double

// a = a + e

a=a+Double(e)

print("\(e)\(a)")

Java

Java

1

2

3

4

5

6

7

8

9

10

11

12

publicclassHelloWorld{

publicstaticvoidmain(String[]args){

finalinte=3;

doublea=5.678;

a=a+e;

System.out.println(e+" "+a);

}

}

Objective-C

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, ...)'"

intmain(intargc,constchar*argv[]){

constinte=3;

doublea=5.678;

a=a+e;

// e + " " + a;

NSLog(@"%d %f",e,a);

return0;

}

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

Swift

1

2

3

4

5

6

7

8

9

10

11

12

13

14

funccalculateMinMaxSum(a:Int,b:Int)->(min:Int,max:Int,sum:Int){

ifa>b{

return(b,a,a+b)

}else{

return(a,b,a+b)

}

}

letstatistics=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

Vim

1

2

3

4

5

6

7

8

9

10

11

load"Int";

funcalculateMinMaxSum(a:int,b:int):int*int*int=

ifa>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(#3statistics));(*Tuples begin inSML at1*)

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)=

ifa>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

Swift

1

2

3

4

5

6

7

letdogLabel="🐶"

letcatLabel="🐱"

letdogCount=1

letcatCount=3

letwholeStr="Hello, I have "+String(dogCount)+" "+dogLabel

+" and \(catCount) "+catLabel+"s";

print(wholeStr)// Hello, I have 1 🐶 and 3 🐱s

Java

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

publicclassHelloWorld{

publicstaticvoidmain(String[]args){

finalStringdogLabel="\uD83D\uDE38";

finalStringcatLabel="\uD83D\uDC36";

finalintdogCount=1;

finalintcatCount=3;

// usual approach

finalStringwholeStr="Hello, I have "+dogCount+" "+dogLabel

+" and "+catCount+" "+catLabel+"s";

// using string interpolation

// produces the same result

finalStringwholeStrInterpol="Hello, I have "+dogCount+" "+dogLabel

+" and "+String.format("%d",catCount)+" "+catLabel+"s";

System.out.println(wholeStr);

}

}

Objective-C

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>

intmain(intargc,constchar*argv[]){

@autoreleasepool{

constNSString*dogLabel=@"\U0001F436";

constNSString*catLabel=@"\U0001F638";

constintdogCount=1;

constintcatCount=3;

// ugly approach

constNSString*wholeStr=

[[[[@"Hello, I have " stringByAppendingFormat:@"%d ",dogCount]

stringByAppendingString:dogLabel]

stringByAppendingFormat:@" and %d",catCount]

stringByAppendingFormat:@" %@s",catLabel];

// more elegant approach

constNSString*wholeStrInterpol=[NSString stringWithFormat:@"Hello, I have %d %@ and %d %@s\n",

dogCount,

dogLabel,

catCount,

catLabel];

NSLog(@"%@\n",wholeStr);

}

return0;

}

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

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

classSomeClass{

varfavLang:String

init(favLang:String){

self.favLang=favLang

}

}

letaClass=SomeClass(favLang:"Assembler")

letbClass=aClass

bClass.favLang="Swift"

print(aClass.favLang)// "Swift"

print(bClass.favLang)// "Swift"

// Struct

structSomeStruct{

varfavLang:String

init(favLang:String){

self.favLang=favLang

}

}

letaStruct=SomeStruct(favLang:"Assembler")

letbStruct=aStruct

bStruct.favLang="Swift"

print(aStruct.favLang)// "Assembler"

print(bStruct.favLang)// "Swift"

Java

SomeClass.java

Java

1

2

3

4

5

6

7

8

9

publicclassSomeClass{

publicStringfavLang;

publicSomeClass(StringfavLang){

this.favLang=favLang;

}

}

Program.java

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

publicclassProgram{

publicstaticvoidmain(String[]args){

finalSomeClass aClass=newSomeClass("Assembler");

finalSomeClass bClass=aClass;

aClass.favLang="Swift";

System.out.println(aClass.favLang);// "Swift"

System.out.println(bClass.favLang);// "Swift"

}

}

Objective-C

SomClass.h

Objective-C

1

2

3

4

5

6

7

8

9

10

11

12

#ifndef SomeClass_h

#define SomeClass_h

@interface SomeClass : NSObject

@propertyNSString*favLang;

-(id)init:(NSString*)comeClass;

@end

#endif /* SomeClass_h */

SomeClass.m

Objective-C

1

2

3

4

5

6

7

8

9

10

11

12

#import <Foundation/Foundation.h>

#import "SomeClass.h"

@implementationSomeClass

-(id) init:(NSString*)favLang

{

self.favLang=favLang;

returnself;

}

@end

main.m

Objective-C

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"

intmain(intargc,constchar*argv[]){

@autoreleasepool{

constSomeClass*aClass=[[SomeClassalloc] init:@"Assembler"];

constSomeClass*bClass=aClass;

aClass.favLang=@"Swift";

NSLog(@"%@\n",aClass.favLang);// "Swift"

NSLog(@"%@\n",bClass.favLang);// "Swift"

}

return0;

}

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

Swift

1

2

3

4

5

6

7

8

funcmakeIncrementer()->(Int->Int){

funcaddOne(number:Int)->Int{

return1+number

}

returnaddOne

}

varincrement=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:

Java

1

2

3

4

5

6

7

8

publicstaticUnaryOperator<Integer>makeIncrementer(){

return(i)->1+i;

}

publicstaticvoidmain(String[]args){

UnaryOperator<Integer>increment=makeIncrementer();

System.out.println(increment.apply(7));// prints 8

}

Switches and Patterns

Swift

Swift

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

letsomePoint=(1,1)

switchsomePoint{

case(0,0):

print("origin")

case(letx,0):

print("I can do sth with the x")

case(-2...2,-2..<6):

print("inside the box")

caselet(x,y)wherex==-y%3:

print("some calculations")

default:

print("nirvana")

}

// prints "inside the box"

Java

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

publicclassPointProgram{

privatestaticclassPoint{

publicfinalintx;

publicfinalinty;

Point(intx,inty){

this.x=x;

this.y=y;

}

}

publicstaticvoidmain(String[]args){

Pointp=newPoint(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");

elseif(p.y==0){

finalinty=p.y;

System.out.println("I can do sth with the x");

}elseif(p.x>=-2&&p.x<=2

&&p.y>=-2&&p.y<6)

System.out.println("inside the box");

elseif(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]

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

Swift

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

letpossibleNumber:String=123

leta:Int?=5// optional variable

letb:Int=6// normal variable

letc:Int!=7// implicitly unwrapped optional

print(a)// "Optional(5)"

print(b)// "6"

print(c)// "7"

letd:Int?=Int(possibleNumber)

lete:Int=Int(possibleNumber)!

letf: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.

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

Swift

1

winSize=house?.windows?.get(2)?.size

Java

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.

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!