Intro

Swift extensions are a great way to add new functionality to existing class, structure, enumeration, or protocol types. If that sounds like something I lifted from Apple’s documentation on Swift extensions it’s because that’s totally a thing I did.

This post is more of a suggestion for when not to use it.

Scenario

Consider this:

class AnObject: Fooable, Barable, Herpable, Derpable {
    // Pretend there's a lot of stuff in here
}

The class AnObject conforms to what looks to be four protocols and depending on these protocols this could end up being a very large object in which to work. There’s got to be a way to better organize this. One that I’ve come across is to use Swift extensions in a single file to break up an object into different sections of conformance. Something like this:

class AnObject {
    // AnObject specific things here
}

extension AnObject: Fooable {
    // Fooable conformance here
}

extension AnObject: Barable {
    // Barable conformance here
}

extension AnObject: Herpable {
    // Herpable conformance here
}

extension AnObject: Derpable {
    // Derpable conformance here
}

Please, for the love of god and all that is holy, do not do this. I know it looks organized. I know it may satisfy a need to separate code out into discrete chunks. However tidy this looks I really think it’s a bad idea and there’s a better way to handle this problem.

What’s the big deal?

Why not use this method? The main reason I want to address is that because of the nature of Swift extensions, this pattern will probably cause inconsistency in our codebase. Everything is uniform if all of our protocols look like:

protocol Foo {
    func bar()
    func zaz()
}

But what about protocols that have variable requirements? Suppose that Barable is defined as:

protocol Barable {
    var somethingOrOther: String? { get set }

    func thisMethodIsntImportant()
    func neitherIsThisOne()
    func stopReadingTheseNames()
}

Oboy. Now we have a variable requirement. What does this mean? It means we need to implement this and now we’ve run into the issue where Swift extensions do not support stored properties. To satisfy this protocol requirement we’ll then need to write the conformance back into the main class definition like so…

class AnObject: Barable {
    // MARK: Barable conformance here
    var somethingOrOther: String?

    func thisMethodIsntImportant() {

    }

    func neitherIsThisOne() {

    }

    func stopReadingTheseNames() {

    }
    
    // MARK: AnObject specific things here
}

extension AnObject: Fooable {
    // Fooable conformance here
}

extension AnObject: Herpable {
    // Herpable conformance here
}

extension AnObject: Derpable {
    // Derpable conformance here
}

Congratulations. We’ve broken our system of pristine organization because of a variable requirement. This doesn’t seem so bad because it’s one protocol that I’m illustrating, but as programs grow we could be looking at two, three, four different protocols in the same situation (this many conformances could also be a bad code smell, but that’s a different topic).

Counterpoint: Computed Properties

“That’s no big deal,” I hear someone say. “You can just have a stored property in the class and use a computed property in the conformance.” Yeah, well ok. Let’s see what that looks like…

class AnObject {
    // AnObject specific things here
    private var hiddenSomethingOrOther: String?
}

extension AnObject: Barable {
    // Barable conformance here
    var somethingOrOther: String? {
        get {
            return hiddenSomethingOrOther
        }

        set {
            hiddenSomethingOrOther = newValue
        }
    }
}

// Imagine the other extensions are below this.

Hoo-ray. We have now introduced:

  1. Two properties (one stored, one computed)
  2. Two methods (the getter and setter)

all to keep splitting our class into extensions.

Mark this down

I’m going to propose a solution that we used quite a bit in Obj-C. Our old friend MARK and you can read more about it at little bites of cocoa. Now we can organize this class into

class AnObject: Barable, Fooable, Herpable, Derpable {
    // -------------
    // MARK: Barable
    // -------------

    var somethingOrOther: String? { get set }

    func thisMethodIsntImportant() {}
    func neitherIsThisOne() {}
    func stopReadingTheseNames() {}
    
    // -------------
    // MARK: Fooable
    // -------------

    func bar() {}
    func zaz() {}

    // --------------
    // MARK: Herpable
    // --------------

    // --------------
    // MARK: Derpable
    // --------------
}

This isn’t new and shiny. It isn’t sexy, fun, or clever. What it is is a consistent way to organize your objects without mixing things up or bending over backwards to keep em separated.