Recently Swift for Tensorflow has picked up some steam, so I wanted to explore the Swift programming language a bit.

The main advantage over Python for Swift is that Swift is very fast by directly using the LLVM compiler infrastructure. Python itself relies a lot on C to make code run fast, but if you write Python code you can get very slow code if it’s not optimized.

However, the main disadvantage for Swift is that it’s ecosystem when it comes to machine learning and data processing libraries is currently a lot less powerful than Python’s ecosystem. This could change in the future, of course.

So let’s check out some of Swifts features and be surprised that it looks in fact not very different from Python code.

Value assignments

Use let to make a constant and var to make a variable. The value of a constant doesn’t need to be known at compile time, but you must assign it a value exactly once. This means you can use constants to name a value that you determine once but use in many places.

When declaring a constant in swift, you use let. If you want the value to be variable, use var instead:

var aVariable = 42
aVariable = 123
let aConstant = 42
let explicitType: Double = 42
let label = "The width is "
let width = 42
label + String(width)

“The width is 42”

In contrast to Python, Swift is a typed language. It allows to infer types dynamically, though, but once a type is established, you cannot assign a value of another type to it.

var test = 42
test = "fortytwo"

“error: cannot assign value of type ‘String’ to type ‘Int’”

Arrays and dictionaries

Using arrays is roughly like Python with the difference that a dictionary is also list-like:

var aList = ["entry1", "entry2", "entry3", "entry4"]
aList[1] = "changedEntry2"
aList.append("entry5")
var dict = [
    "bart": "simpson",
    "homer": "simpson",
]
dict["marge"] = "simpson"
for (k,v) in dict {
    print(k, v)
}

bart simpson
homer simpson
marge simpson

Loops and conditionals

Except for using braces instead of indentation, it looks very Python like:

 let numbers = [1, 2, 3, 4, 5, 6]
 var oddNumberCount = 0
 for number in numbers {
     if number % 2 == 1 {
         oddNumberCount += 1
     }
}
oddNumberCount

3

One thing I noted which is quite different from Python is the usage of so-called Optionals. It’s a variable which indicates that it might have a value of a specific type or be None (which is called nil in Swift) and this is achieved by putting a question mark after the type. You can then use the ?? operator to fall back to a default value if the Optional is nil:

var user: String? = nil
let fallback: String = "Guest"
print("Hi \(user ?? fallback)")
user = "User42"
print("Hi \(user ?? fallback)")

“Hi Guest”
“Hi User42”

Ranges

Instead of the Python range operator, Swift uses custom syntax. When using ..<, then the range is non-inclusive (like range in Python) and when using ... the range includes the upper value.

for number in 1..<3 {
  print(number)
}

1
2

for number in 1...3 {
  print(number)
}

1
2
3

Functions and Closures

Swift uses func instead of def to declare a function. The syntax is just as if you use types in Python with -> to separate the parameter names and types from the function’s return type.

func hello(name: String, greeting: String) -> String {
    return "\(greeting) dear \(name)."
}
hello(name: "Reader", greeting: "Moin")

“Moin dear Reader.”

One odd thing to note: the parameters need to be passed in the exact order as they were defined. So this doesn’t work:

hello(greeting: "Moin", name: "Reader")

“error: argument ’name’ must precede argument ‘greeting’”

You can nest functions just like in Python and they also use closures as you are used to:

func returnFifteen() -> Int {
    var y = 10
    func add() {
        y += 5
    }
    add()
    return y
}
returnFifteen()

15

Functions can return other functions, the syntax might look a bit odd at first:

func getTextCounter() -> ((String) -> Int) {
    func countLength(text: String) -> Int {
        return text.count
    }
return countLength
}

var textCounter = getTextCounter()
textCounter("This is a demo text.")

20

Lambda functions are written using {} braces and can nicely be used in maps:

let numbers = [1, 2, 3, 4]
numbers.map({ (number: Int) -> Int in
    let result = 5 * number
    return result
})

▿ 4 elements
- 0 : 5
- 1 : 10
- 2 : 15
- 3 : 20

But you can also write it less verbose:

let mappedNumbers = numbers.map({ number in 5 * number })
print(mappedNumbers)

[5, 10, 15, 20]

Instead of using a name, you can also refer to the parameters in a closure by number. When a closure is the only argument to a function, you need no regular brackets:

let sortedNumbers = numbers.sorted { $0 > $1 }
print(sortedNumbers)

[4, 3, 2, 1]