Back in 2016, well before Swift had native async/await, asynchronous code in
Swift looked a lot like asynchronous code in Objective-C: closures nested inside
closures nested inside closures, with every async API forcing you to wrap the
next step of your logic in another callback. Brisk was my attempt to hide that
mess behind a small DSL.
The core idea was a handful of custom infix operators that let you write
async-feeling code in a synchronous-looking flow. <<+ would call an async
function and block until it returned on the main queue, <<~ would do the same
on a background queue, +>> would dispatch a closure asynchronously to main,
and so on. So instead of this:
findClosestPokemon { pokemon, error in
countPokeballs { number, error2 in
throwPokeballAt(pokemon: p) { success, error3 in
completionHandler(success: success, error: error3)
}
}
}
You could write something like this:
myQueue.async {
let (pokemon, error) = <<+{ findClosestPokemon(completionHandler: $0) }
let (number, error2) = <<~{ countPokeballs($0) }
let (success, error3) = <<+{ throwPokeballAt(pokemon: p, completionHandler: $0) }
completionHandler +>> (success: success, error: error3)
}
I also threw in some convenience extensions on DispatchQueue — delayed
execution, repeated execution, deduplicated once(operationId:) calls — for
the kinds of GCD patterns I kept rewriting from scratch in every project.
Brisk had a pretty short shelf life. Once Swift 5.5 landed with real
async/await, everything Brisk was solving became a language feature, and
the operators stopped playing nicely with newer Swift compilers anyway. I
mothballed it.