Some thoughts and considerations that led to design decisions.

Promise specs

There are quite a few implementations out there. All with their strength and weaknesses and adapted to the language their written in. It's tempting to follow an existing spec like Promises/A+. I have chosen not to follow this because I think it doesn't play well with Kotlin.

For instance, the Promises/A+ spec defines then as

promise.then(onFulfilled, onRejected)

where onFulfilled and onRejected are two function arguments. Both are basically bind methods on either the left or right side of a promise. This introduces some challenges that are hard to overcome. The biggest one is how to handle errors thrown from the onFulfilled or onRejected method. The Promises/A+ states the following:

If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.

This means 1 promise can actually resolve in 3 states instead of the probably expected 2, which are:

I don't think this makes much sense and is not what expected when using the API. Therefor the signature for Kovenant's then function is:

fun <V, R> Promise<V, Exception>.then(bind: (V) -> R): Promise<R, Exception>

Any Exception from the bind method is considered a rejection and a successful computation a fulfillment. That way the Promise resolves in just 2 states. Kovenant's then behaves quite similar to Option/Maybe/Try types for that matter.

So reason enough to not follow the Promises/A+ spec.

Top level functions

One important consideration is the use of top level functions versus class or object bound functions. To illustrate:

task {
Kovenant.task {

the latter has the advantage that it doesn't interfere with other frameworks that introduces such methods. But on the other hand how many frameworks bringing async functionality does a project really need? So I decided to stick with top level functions, which need to be imported explicitly anyway, to keep things simple.


I started off with an implementation that was partly written in Java and used the sun.misc.Unsafe class. The upside was that it was quick and very memory efficient. The downside that it requires proprietary API. So I decided that using a generic code base outweighs the performance and memory efficiency gains. As a bonus everything is written in pure Kotlin now.