Experiments with Swift Generics

Note: I’m going through draft posts that go back to 2014 and publishing where they still may have value. They may not be 100% upto date but better published late than never.

Generics are interesting within Swift. Syntactically they look the same as most other languages which supports generics. So, we have the syntax below

class Policy<TResult> {
}

Generic and non-generic types of the same name

In C# we can essentially create a generic and non generic type and the compiler works out which we meant to use. Sadly this doesn’t exist in Swift (or Java or maybe many other implementations). But then, rather interestingly we can (assuming no constraint on the generic parameter) actually create a generic of type Void, i.e.

class Test<TResult> {
  func run(_ action: () -> TResult) -> TResult {
    return action()
  }
}

and then write code like this

let a1 = Test<String>()
let a2 = a1.run({ return "Hello" })

let b1 = Test<Void>()
let b2 = b1.run({ return })

What about, if we looked at this problem from the perspective of creating a default type for the generic. Swift doesn’t support this but we can (sort of) create something like this using init. Where we take an argument of the generic type, so for example if we have

class Test<T> {
  init(value: T) {
  }
}

Okay so we can now declare our variables like this

let t1 = Test(value: 42)
let t2 = Test(value: "Hello")

I know, this doesn’t have a default implementation at all, so instead we’ll create an extension which does the defaulting for us

extension Test where T == Person {
    convenience init() {
        self.init(value: Person())
    }
}

Now we create an instance like this

let t3 = Test()

See Can I assign a default type to generic type T in Swift? for further information on this one.

Adding constraints

We can add a constraint, for example the generic type must a a type of Error, like this

class Test<TError: Error> {
}

We can also create constraints against properties of a type, for example at a function level we can check or (as above) on extensions using the where clause. So in the example

extension Test where T == Person {
}

The extension implicitly knows that there’s a generic parameter T and so we don’t need to redeclare it, instead we’re simply saying this extension works for Test where T is a Person. This sort of technique can also be used within functions.

Default value

If you come from a C# background, you’ll probably be used to using default(T) or the shortened version simply default. Swift doesn’t include such a keyword. Instead you’ll either need to use optionals, i.e. returned a .some or .none, or ofcourse you might create a function of class to imitate such functionality yourself.