Generics, extensions, and where clauses: 😱

While trying to implement something completely different and unrelated to the code in this post, I found myself thinking really hard about the combination of Swift generics, protocols, and protocol extensions. But that is not the theme of this post.

But, usually one thing leads to another. At least, that’s what happens usually when I think hard about something: I end up figuring out something completely different. In this case, I’ve just noticed this:

final class Salmon {
    func bake() {
        print("baking salmon")
    }
}

final class Beef {
    func roast() {
        print("roasting beef")
    }
}

final class Oven<T> {
    let thingToCook: T

    init(stuff: T) {
        thingToCook = stuff
    }
}

extension Oven where T: Salmon {
    func cook() {
        thingToCook.bake()
    }
}

extension Oven where T: Beef {
    func clean() {
        print("Cleaning oven, only when cooking beef")
    }
    
    func cook() {
        thingToCook.roast()
        clean()
    }
    
}

let salmonOven = Oven<Salmon>(stuff: Salmon())
let beefOven = Oven<Beef>(stuff: Beef())

// The compiler will say nononono to this
//salmonOven.clean()


salmonOven.cook()
beefOven.cook()

From a purely grammatical point of view, the code makes perfect sense, but I am not sure if there is a real use case for it, at least a use case than can not be solved applying traditional polymorphism (i.e. using interfaces/protocols the way your favourite deity meant them to be used), but well, there it is.

And here is the playground, just in case: GenericsExtensions.playground

Leave a Reply

Your email address will not be published. Required fields are marked *