Release of KAsync 0.1.0

I’m pleased to announce KAsync 0.1.0.

KAsync is a library to write composable asynchronous code using lambda-based continuations.

In a nutshell:

Instead of:

class Test : public QObject {
    Q_OBJECT
public:
    void start() {
        step1();
    }
public signals:
    void complete();
private:

    void step1() {
        .... execute step one
        QObject::connect(step1, Step1::result, this, Test::step2);
    }

    void step2() {
        .... execute step two
        QObject::connect(step1, Step1::result, this, Test::done);
    }

    void done() {
        emit complete();
    }

};

you write:

KAsync::Job step1() {
    return KAsync::start([] {
        //execute step one
    });
}

KAsync::Job step2() {
    return KAsync::start([] {
        //execute step two
    });
}

KAsync::Job test() {
    return step1().then(step2());
}

The first approach is the typical “job” object (e.g. KJob), using the object for encapsulation but otherwise just chaining various slots together.

This is however very verbose (because what typically would be a function now has to be a class), resulting in huge functional components implemented in a single class, which is really the same as having a huge function.

The problem get’s even worse with asynchronous for-loops and other constructs, because at that point member variables have to be used as the “stack” of your “function” and the chaining of slots resembles a function with lot’s and lot’s of goto statements (It becomes really hard to decipher what’s going on.

KAsync allows you to write such code in a much more compact fashion and also brings the necessary tools to write things like asynchronous for loops.

There’s a multitude of benefits with this:

  • The individual steps become composable functions again (that can also have input and output). Just like with regular functions.
  • The full assembly of steps (the test() function), becomes composable as well. Just like with regular functions.
  • Your function’s stack doesn’t leak to class member variables.

Additional features:

  • The job execution handles error propagation. Errors just bubble up through all error handlers unless a job reconciles the error (in which case the normal execution continues).
  • Each job has a “context” that can be used to manage the lifetime of objects that need to be available for the whole duration of the execution.

Please note that for the time being KAsync doesn’t offer any API/ABI guarantees.
The implementation heavily relies on templates and is thus mostly implemented in the header, thus most changes will require recompilation of your source code.

If you’d like to help out with KAsync or have feedback or comments, please use the comment section, or the phabricator page.

If you’d like to see KAsync in action, please see Sink.

Thanks go to Daniel Vrátil who did most of the initial implementation.

Tarball

Advertisements

Author: cmollekopf

Christian Mollekopf is an open source software enthusiast with a special interest in personal organization tools. He started to contribute actively to KDE in 2008 and currently works for Kolab Systems leading the development for the next generation desktop client.

4 thoughts on “Release of KAsync 0.1.0”

  1. Some questions based on a cursory look at the code, as I don’t fully grasp how it all fits together:

    Am I correct in understanding the Job as a C++ implementation of the ES6 Promise concept? Does the implementation cover catching exceptions and forwarding them to the error handling continuation as well?
    Is it possible to flatten a Future implicitly, that is if your lambda returns a Job, will the result/error output be flattened into the context of the outer Future? (The reason you might want this is: you could have a Future/Promise doing a network request, then examining some status code and based on that decide to short circuit with an error or continue with a new Future doing the parsing of the response payload; but from the outside you would interact with the normal continuation instead of having to nest and return to callback hell.)

    Are there any plans to support the concept of a stream of partial results? That way you’d also have something feeling very similar to the Observable idea, which is generally useful when dealing with asynchronous events or partial results.

  2. Yes, I think it works pretty much like the ES6 Promise.

    Exceptions are not handled yet. It wouldn’t be hard to catch exceptions from the continuation if we knew which, but if the continuation executes further steps via event-loop we don’t really have any way to catch those exceptions.

    Yes, you can return jobs from a continuation, which will essentially be the same as chaining two jobs with .then(). This also works in error handler continuations, so the handler can either do some cleanup work, clear the error handler or forward the error. So to the user of a job it is fully transparent what the subjob exactly does, it only cares about the result.

    I thought about streaming of results but I couldn’t find a way to add that to KAsync in a sensible way. What I’m doing right now if I need that is to just implement that externally, e.g. through a heap allocated list that I slowly fill with results (I guess something like that could be implemented with a “yield” callback that can be called repeatedly). If you have ideas on how that could work well, I’d be interested to hear about them.

    1. I was thinking of something akin to the ‘Observable’ pattern, also popularised in ES6. I’m not talking full-on FRP semantics like in the Eliott paper (e.g. reactive-banana), but something ‘just enough’ like that so you could do the pub/sub & operator patterns with it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s