Currying Initialisers in Swift
Being chef curry IRL
Here’s a scenario I commonly encounter while building apps here at Kayako — there’s this one object (or array of objects) I have to initialise, and it involves multiple API calls running in parallel (or serially, depending on the situation).
Now, this seems straightforward enough. Wait until you have all the data ready(stored in a global variable or something), and initialise the object. Right?
Well, yeah. But what if I want to not write
let x = Obj(a:1, b: 2, c:3, and so on.....)
And not create global variables. What if.. I want a swiftier solution?
Well, here’s a solution
By using currying to initialize objects partially, and doing a full initialization once more information is available, it helps you (the awesome Swift 🔶 Developer), write clear and succinct code and save time in the long run.
The code
So, let’s say you have a Car Object. We’ll use a struct because “Viva la value types!”, and immutability = ❤
A Motorcycle(or bike) can be thought of as engines + tires
//: For ease. Also, named tuples are 🔥🔥🔥
typealias TirePair = (front: Tire, back: Tire)//: Stupid Medium won't let me indent my code properly 😡
struct Engine {let horsePower: Intlet make: String}struct Tire {let diameter: Float}
And our Bike Class
struct Bike {let engine: Enginelet tires: TirePair//: This is the only function that's neededstatic func generateBike(engine: Engine, tires: TirePair) -> Bike {return Bike(engine: engine, tires: tires)}}
If you curry this using something like thoughtbot’s awesome library Curry
let curriedInit = curry(Bike.generateBike)
And we can partially initialize it like so
//: This can also be in the callback function of an APIlet engine = Engine(horsePower: 12, make: "asdfkjnadsf")let partialBike = curriedInit(engine)
And then simply pass in a TirePair and voila! We have a full Bike ready to go
//: Second API Call
let tirePair = (front: Tire(diameter: 12), back: Tire(diameter: 14))let fullBike = partialBike(tirePair)
//: Yay!
It’s pretty elegant, shortening your code while still retaining the type safety from swift we know and love (and curry is a single file framework, so file size isn’t a problem).
If there’s any advantages I’ve missed out, or if someone’s implemented something similar in production, I’d love to hear you in the responses below.
Oh, and a recommend would be nice too 👇