---
title: QCoro 0.5.0 Release Announcement
date: "2022-04-25"
description: >
    Major feature in the 0.5.0 release are .then() continuations for Task<T>, all asynchronous
    operations in QCoro returning Task<T> and many operations have gained support for optional
    timeout argument. Last but not least, coroutine-friendly wrapper for QThread has been
    introduced.
---

<!--
SPDX-FileCopyrightText: 2022 Daniel Vrátil <dvratil@kde.org>

SPDX-License-Identifier: GFDL-1.3-or-later
-->

# QCoro 0.5.0 Release Announcement

Major features:

* .then() continuation for `Task<T>`
* All asynchronous operations now return `Task<T>`
* Timeouts for many operations
* Support for `QThread`

## .then() continuation for Task<T>

Sometimes it's not possible to `co_await` a coroutine - usually because you need to integrate with a 3rd party code
that is not coroutine-ready. A good example might be implementing `QAbstractItemModel`, where none of the virtual
methods are coroutines and thus it's not possible to use `co_await` in them.

To still make it possible to all coroutines from such code, `QCoro::Task<T>` now has a new method: `.then()`,
which allows attaching a continuation callback that will be invoked by QCoro when the coroutine represented
by the `Task` finishes.

```cpp
void notACoroutine() {
    someCoroutineReturningQString().then([](const QString &result) {
        // Will be invoked when the someCoroutine() finishes.
        // The result of the coroutine is passed as an argument to the continuation.
    });
}
```

The continuation itself might be a coroutine, and the result of the `.then()` member function is again a `Task<R>`
(where `R` is the return type of the continuation callback), so it is possible to chain multiple continuations
as well as `co_await`ing the entire chain.

## All asynchronous operations now return `Task<T>`

Up until now each operation from the QCoro wrapper types returned a special awaitable  - for example,
`QCoroIODevice::read()` returned `QCoro::detail::QCoroIODevice::ReadOperation`. In most cases users of QCoro do
not need to concern themselves with that type, since they can still directly `co_await` the returned awaitable.

However, it unnecessarily leaks implementation details of QCoro into public API and it makes it harded to return
a coroutine from a non-coroutine function.

As of QCoro 0.5.0, all the operations now return `Task<T>`, which makes the API consistent. As a secondary effect,
all the operations can have a chained continuation using the `.then()` continuation, as described above.

## Timeout support for many operations

Qt doesn't allow specifying timeout for many operations, because they are typically non-blocking. But the timeout
makes sense in most QCoro cases, because they are combination of wait + the non-blocking operation. Let's take
`QIODevice::read()` for example: the Qt version doesn't have any timeout, because the call will never block - if
there's nothing to read, it simply returns an empty `QByteArray`.

On the other hand, `QCoroIODevice::read()` is an asynchronous operation, because under to hood, it's a coroutine
that asynchronously calls a sequence of

```cpp
device->waitForReadyRead();
device->read();
```

Since `QIODevice::waitForReadyRead()` takes a timeout argument, it makes sense for `QCoroIODevice::read()`
to also take (an optional) timeout argument. This and many other operations have gained support for timeout.

## Support for `QThread`

It's been a while since I added a new wrapper for a Qt class, so QCoro 0.5.0 adds wrapper for `QThread`. It's
now possible to `co_await` thread start and end:

```cpp
std::unique_ptr<QThread> thread(QThread::create([]() {
    ...
});
ui->setLabel(tr("Starting thread...");
thread->start();
co_await qCoro(thread)->waitForStarted();
ui->setLabel(tr("Calculating..."));
co_await qCoro(thread)->waitForFinished();
ui->setLabel(tr("Finished!"));
```

## Full changelog

[See changelog on Github](https://github.com/danvratil/qcoro/releases/tag/v0.5.0)

<hr>

Thanks to everyone who contributed to QCoro!
