Swift for Web Developers

Dec. 16, 2017 • 10m 48s

Swift has become a standard language for iOS development and is becoming a popular language for server side programming as well. My previous programming experience is mostly with PHP and JavaScript, so Swift was a whole new world when I started. I’m writing this post to give web developers coming from PHP, Python or Ruby a head start on how to use Swift.

Installation

MacOS

Installing Swift on a Mac is super easy. Just install Xcode! It has a great playgrounds feature for trying out the language.

Linux

To use Swift on Linux, just follow the instructions on Swift.org to download and run the compiler. Alternatively, a Docker image is available for running Swift.

Windows

If you are on Windows 10, you could install Swift in the Linux Subsystem, but the easiest method would be to install the Docker image mentioned above.

Where is My Semi-colon?

print("Hello, world!")

The first thing you will notice is that Swift doesn’t require semi-colons at the end of each line, similar to Ruby or Python. Swift was built with both scripting languages and compiled languages in mind, so you will see different features of both types in the language.

Also, similar to Ruby and Python, you don’t have to use parentheses in conditionals, but you do use brackets to surround the contents of the block like Java and PHP.

if true {
    print("It is true")
}

Swift uses the same structure for loops.

let fruits = ["Apple", "Pear", "Orange"]
for fruit in fruits {
    print("My favorite fruit is: \(fruit)")
}

let vs var

In Swift, data names can be declared with two different words: let and var. Unlike ES6 JavaScript, let is for constants and var is for regular variables. The value of a let constant cannot be changed after it is set, but a var can be changed as needed.

If you write the following code, you will get an error:

let name = "Andrew"
name = "not Andrew"

But, the following is acceptable:

var count = 1
count = 2

The Swift compiler will give you a warning if you create a variable and then never change it, so it is best practice to start with a constant and change it to a variable only when it needs to become something else.

Swift Loves Types

Everything in Swift is statically typed, but the types are inferred like Go or Rust. Type inference basically means that the compiler figures out the type of a variable based on its initial value. So, if you try to create a constant or variable without a type defined, you must set it’s value immediately so the compiler know what type it is.

For example, if you run this code, you will get an error.

let favoriteMovie
favoriteMovie = "Return of the Jedi"

You have to either declare the constant type or set the constant immediately.

let favoriteMovie: String
favoriteMovie = "Return of the Jedi"

let secondFavoriteMovie = "The Empire Strikes Back"

Swift has types for all standard pieces of data: Int String Float Double Bool and more.

Parameter Names!

One of my favorite features of Swift is parameter naming. When you create a function and name the parameters, the code calling the function has to name the parameters as well.

func sayHello(greeting: String) {
    print(greeting)
}

sayHello(greeting: "Hola!")

Once you get used to it, it makes your functions much more expressive. If you don’t want to have named parameters, you can put an _ in front of the name to omit it.

func sayGoodbye(_ goodbye: String) {
    print(goodbye)
}

sayGoodbye("Adios!")

In the Swift standard library, you will see functions written both ways depending on the situtation so that is a good reference to use to write your own functions.

What Is Up with the Question Marks?

If you have read any Swift code before, you probably have noticed several instances where a question mark is used. A question mark is used to create a special type and it basically means the value can be either a type or nil. For example, if a variable is declared like var optional: String?, it means optional can be either a String or nil.

Now, optionals require a little more work to get the value. To use a variable with an optional type, you have to unwrap the value.

let optional: String? = "I am an optional"
if let value = optional {
    print(value)
}

By using an if statement, you are verifying that the value in the optional is not nil and if so, it is set to value to be used within the if block.

You can also unwrap an optional by using a guard statement.

enum OptionalError: Error {
    case optionalIsNil
}

let value: String? = nil
guard let name = value else {
    throw OptionalError.optionalIsNil
}

A guard statement attempts to unwrap the value into the name constant, but if it returns nil, it runs the content of the block. In this case, because value is nil, the guard block throws a customer error indicating something went wrong.

Optionals can be confusing the first time you use them and you may be asking, why use them then? The goal of optionals, is to make sure your code handles every situation where your constants and variables could be nil. Let’s say that you have a function which gets the current user from a session, you will want to handle the situation where the session is empty.

func getCurrentUser(session: Session) -> User? {
    if session.has("currentUser") {
        return session.get("currentUser")
    }

    return nil
}

let session = Session()
if let user = getCurrentUser(session: session) {
    print(user.name)
}

In this case, getCurrentUser could return nil so we are only printing the user’s name if the value returned from the function actually is a User object. If we didn’t check for nil, we would have a runtime error because no name would exist. In the end, the goal of optionals is to make your code more correct.

Struct vs Class

As you start coding in Swift, you will notice that there are two constructs that look almost the same. Here is an example:

struct CarSize {
    var height: Double
    var width: Double
    var length: Double

    init(height: Double, width: Double, length: Double) {
        self.height = height
        self.width = width
        self.length = length
    }

    func getArea() -> Double {
        return width * length
    }
}

class Car {
    var make: String
    var model: String
    var color: String

    init(make: String, model: String, color: String) {
        self.make = make
        self.model = model
        self.color = color
    }

    func getType() -> String {
        return "\(make): \(model)"
    }
}

let carSize = CarSize(height: 10, width: 10, length: 20)
let car = Car(make: "Chevrolet", model: "Corvette", color: "Red")

Both structs and classes are used to create custom types that can contain properties and methods. So what is the difference?

First, only a class can inherit from another class. A struct cannot inherit from a struct. If you require any type of inheritance, then you must use a class.

Second, instances of a class are passed by reference and instances of a struct are passed by value. Basically, that means they are stored in memory differently. When you create an instance of a class, the variable holding the instance does not actually contain the instance, it contains a memory id which is a reference to where the instance exists in memory. A variable holding an instance of a struct, actually holds the struct, not just a reference. Therefore, when you pass a class instance into a function, the function receives a reference to an object, but when you pass a struct instance into a function, it receives a copy of the struct. There are advantages and disadvantages to either scenario, so choosing a struct or class depends on what you are trying to accomplish.

In the end, structs are typically used for wrapping simple data values, like the CarSize in the example and classes are used for anything else which may include types that change often or have mutating methods. Apple recommends using classes in most cases.

Conclusion

I hope this quick rundown helps you understand some of the Swift concepts more quickly. I recommend reading Apple’s The Swift Programming Language book to learn more. Please post a comment if you any questions.

Happy Swifting!