Fetch it, Change it, Merge it: Code it

TL;DR: You can build flows by coupling protocols with associated types.

Let`s talk about writing code. When writing code, you gotta be lazy. Pretty ambiguous but correct in every sense. Being lazy in the sense of “shy of writing code” can be awesome.

  • Not having written much LOC speeds up understanding your own code
  • Not wanting to write much code lets you think more about the structure of your code

Shenanigans!

Let`s talk about protocols. It often appears that the data in your app has some kind of flow. Between all those ifs and elses, somewhere deep down is a spine. It better be strong and hard to stand all your pretty features you add. In order to embrace safety of your data flow, let’s define a pretty simple flow in form of protocols.

Pro: Protocols 👍

I will not give an explanation what protocols are - so this might be a good point to ensure you have read the Swift Documentation about Protocols. Lets jump into some totally reasonable definitions:

// Fetchable
protocol Fetchable {
  // a placeholder for what type we wanna fetch
  // should be associatedtype if swift 2.2
  typealias FetchedType
  // static access for all elements
  static var all: [FetchedType] { get }
}

ok - next up:

// Changeable
protocol Changeable {
  // a placeholder for what type we wanna as a result after the change
  // should be associatedtype if swift 2.2
  typealias ChangeResultType
  // static access for a closure to modify Self to ChangeResultType
  static var changeTo: Self -> ChangeResultType { get }
}

ok - finally:

protocol Mergeable {
  // a placeholder for what type we wanna as a result after the merge
  // should be associatedtype if swift 2.2
  typealias MergeResultType
  // static access for a closure to merge Self with MergeResultType
  static var merge: (MergeResultType, Self) -> MergeResultType { get }
  // static access to a initial merge value
  static var identity: MergeResultType { get }
}

Thats its. Thats all we know. No interconnection until now.

Those protocols dont know each other - so they are super-reusalble™. And of course, it is possible to use funcs instead of closures, but its a lazy post.

Give it a good stir to combine 🍰

Now comes the first part that will boost productivity. Lets define a func where all those protocols work together.

// Lets start by extending Fetchable
extension Fetchable where 
  // ensuring the fetched type is also Changeable
  Self.FetchedType: Changeable,
  // and the result of the change is Mergeable
  Self.FetchedType.ChangeResultType: Mergeable { 
  
  /// some litle shortcuts
  typealias MergeableType = Self.FetchedType.ChangeResultType
  typealias ChangeableType = Self.FetchedType

  /// the static method has access to all known Protocol Types from the extension definition.
  /// lets run them all 
  static func fetchItChangeItMergeIt() -> MergeableType.MergeResultType {
    // fetch it
    return all
      // change it
      .map(ChangeableType.changeTo)
      // merge it
      .reduce(MergeableType.identity, combine: MergeableType.merge)
  }
  
}

So far - all valid swift - but nothing will happen. 🙄

All that was defined so far is based on protocols. There is no actual implementation of the protocols. But in terms of the abstract protocol flow we already know what happens.

This is like a universal truth in our code. And universal truth is great.

With less code comes great responsibility 🎩

In fact - using those protocols is the most boring part. There is hardly something to do. Not kidding.

extension String: Fetchable, Changeable {
  // yay...  
  static let all = ["a", "b", "c"]
  // yay...
  static let changeTo: String -> Int = { $0.characters.count }
}

extension Int: Mergeable {
  // yay...
  static let identity = 0
  static let merge: (Int, Int) -> Int = (+)
}

String.fetchItChangeItMergeIt()
/// -> 3

The point is:

  • You have to know when to use those things. It`s like typesafe loosely coupled power.
  • Plus you need the right abstraction for the types. Like in the example on the top you cannot define another String that is Changeable to String. You have to workaround those situations by Types.

Have fun playing ⛳️

Running in Playground:

Playground

👻 Feel free to hit me on twitter. @elmkretzer