How to use Swift literals with custom types

Literals are combination of raw letters, characters and numbers that enable types to be constructed easily, below is a simple example of some common literals

let myString = "Hello World"
let myNumber = 34
let myDouble = 28.75

In above code example we have created three different variables using string, integer and double literals. In almost all programming languages there is support for literals and swift is of no difference. Swift even goes one step ahead, through use of its protocol oriented approach which allows any type to be able to initialise from literals.

Swift provides a set of protocols to work with literals as part of standard library here. All literal types from swift standard library can be divided into three different categories. Collection literals(arrays and dictionaries), value literals (int, float, bool and nil) and string literals.

Let’s consider a few examples how we can use swift initialisation with literals protocols to work with any custom type.

String Literals

struct Person {
    let firstName: String
    let lastName: String
}

Without using literal, an instance of above structure can be created as below

let person = Person(firstName: "Khurram", lastName: "Shehzad")

In order for our custom type to be able to initialize with literal we have to adopt to the literal protocol from which we want our custom type to be initialized from. For Person struct we will use ExpressibleByStringLiteral protocol to make it work with string literals.

struct Person: ExpressibleByStringLiteral {
    typealias StringLiteralType = String
    init(stringLiteral value: StringLiteralType) {
        let components = value.components(separatedBy: .whitespaces)
        firstName = components[0]
        lastName = components[1]
    }
    let firstName: String
    let lastName: String
}

Now we can easily create an instance of Person using string literal

let person: Person = "Khurram Shehzad"

Please note that we have explicitly mentioned the type. If we do not mention the type the swift compiler will use default type. For ExpressibleByStringLiteral the default type is String. Other protocols in for String literals are

Value Literals

Similarly we can have our custom types adopt to value literal as well. In the next example we have our custom type Temperature that is initialized from a Int value literal namely ExpressibleByIntegerLiteral

struct Temperature: ExpressibleByIntegerLiteral {
    typealias IntegerLiteralType = Int
    init(integerLiteral value: Int) {
        t = value
    }   
    let t: Int
}

let waterFreezing: Temperature = 0

Swift type inference system can work with literals when used with custom data types, as below

func waterBoilingTemperature() -> Temperature {
    return 100
}
let waterBoiling = waterBoilingTemperature() 

Note that swift type inference system will work here, as type is clearly evident from return type of function and we do not have a need to mention type explicitly at calling side.

Other protocols in value primitive literals are

Collection Literals

Swift standard library has also support for array and dictionary literals in ExpressibleByArrayLiteral and ExpressibleByDictionaryLiteral protocols respectively. Below is a simple example to use array literal.

class LinkedList: ExpressibleByArrayLiteral {
    var first: Node?
    class Node {
        var value: Int?
        var next: Node?
    }
    typealias ArrayLiteralElement = Int
    required init(arrayLiteral elements: Int...) {
        var current: Node?
        for element in elements {
            if first == nil {
                first = Node()
                first?.value = element
                current = first
            } else {
                let node = Node()
                node.value = element
                current?.next = node
                current = node
            }
        }
    }
}

let linkedList: LinkedList = [1, 2, 3, 4, 5]

Here we are initialising our custom linked list from swift array literal.

Similarly we can use ExpressibleByDictionaryLiteral for initialising from dictionary literal as well. Below is an example of utilising dictionary literal in custom type.

struct SolarSystem {
    struct Planet {
        let name: String
        let moonsCount: Int
    }
    let planets: [Planet]
}

extension SolarSystem: ExpressibleByDictionaryLiteral {
    typealias Key = String
    typealias Value = Int
    init(dictionaryLiteral elements: (String, Int)...) {
        var planets = [Planet]()
        for element in elements {
            planets.append(Planet(name: element.0, 
                                  moonsCount: element.1))
        }
        self.planets = planets
    }
}

let ourSolarSystem: SolarSystem = [
   "Mercury": 0, 
   "Venus": 0, 
   "Earth": 1, 
   "Mars": 2, 
   "Jupiter": 79, 
   "Saturn": 82, 
   "Uranus": 27, 
   "Neptune": 14]

For a complete list of available literals that you can use for you own custom types please see documentation here.

All the above code examples can be found here.

If you liked the article please consider sharing by using the share button below. Also please subscribe to mailing list to get latest updates immediately.