The idea of having a container for a value that is not yet present, but will be available sometime in the future is a powerful one. Unlike call-callbacks, it decouples the asynchronous process invocation from the result handler. This allows creating nicer asynchronous APIs than the usual approaches.
The Qt library provides a container like this – the
And, at the same time, it provides incompatible special-cases containers like
QDBusReply<T> and other
QFuture was meant to be used only in the QtConcurrent library,
and was designed to suit that need –
to wrap operations executed concurrently on multiple threads.
It was moved to QtCore in 5.x,
but apart from the rellocation,
it did not receive much love,
and its design stayed the same.
Issues with waiting
In order to do something with the result, you need to wait for the future to arrive. It you do not want to block your main thread, you need to wait for the future like this:
This makes using QFuture a pain. I’ve been creating wrappers for this on multiple occasions, and realised that I do it often enough to warrant creating a new library.
Issues with creation
Another issue with QFuture is that Qt does not really use it.
The previously mentioned classes like
QDBusReply are a perfect example.
Imagine you are writing an interface library for some
You can make it blocking
which is very bad since the service might take a long time to respond.
You can make it asynchronous by returning QDBusReply
which exposes the implementation detail via the API. Also a very bad approach.
Or, you can split it into a request slot and a response signal
which is plain ugly to write and use.
QFuture<QString> is used instead,
you get exactly what you need
it is asynchronous,
it hides all the implementation details
(the user does not know whether it uses DBus,
executes an external process and returns its output, etc.)
and it is not ugly.
The problem is that Qt does not provide
a way to allow you to convert these different future-like constructs
This is the second reason behind the creation of the AsynQt framework.
What is AsynQt?
The aims of the framework are:
- To provide wrappers for common Qt future-like classes
- To add methods for easier manipulation of
I’ve implemented wrappers for the DBus and
You can convert the
QDBusReply<T> to a
QFuture<T> simply by
makeFuture template function,
or you can invoke a DBus method and get the
as the result immediately:
QProcess wrapper is a bit trickier because it has one special feature.
Apart from the process, it receives a function that
allows you to extract the information you want to return from the process,
instead of returning the
Examples are worth more than words:
There are also a few convenience methods for creating simpler futures
makeReadyFuture that creates a future which already contains a value,
makeCanceledFuture that creates a canceled future and
makeDelayedFuture which creates a future that will contain
the specified value after the specified duration of time.
And more will come.
Now, all of the above would not be that useful
if we still had to use the usual
For this reason,
a few new methods are provided –
I’ll leave the explanation of these for later
(when I add a couple more different ones
that I consider necessary).
At this time, just a few examples:
Pipe or range syntax
The library also supports the pipe syntax. Instead of calling a transformation on a future directly, you can also send the future through a pipe to the transformation.
It is under heavy development.
The aforementioned things work,
but the API might not be stable still.
I’m still deciding whether some of the names
are the best possible
It is implemented as mostly a header-only library, I’m still wondering whether I ought to remove the ‘mostly’ part.
It should be compilable by any compiler that supports
static_assert, lambdas and similar.
Nothing fancy, but I am not able to test whether
it can be compiled on windows at this time.
The code is in my scratch space at firstname.lastname@example.org:scratch/ivan/libasynqt