April 07, 2025 by Alexei Cazacov | Comments
In this blog post, I would like to talk about the improvements in documentation navigation you can see in the Qt Framework's documentation for the Qt 6.9 release.
Previously, our documentation portal relied mostly on searching: you type a request and get the results. This works well if you know how the things are named in the Qt world. But if you switch to Qt from a different platform, how do you know what to enter in the search box? What if you want to explore the features of a particular module? In this case, you need to have better navigation in Qt docs.
In Qt 6.9, we reorganized the documentation structure for each module in Qt Creator's help viewer.
In the Qt Creator's help viewer, you can find all the topics we have for each module organized in a tree structure.
We added a common navigation tree for the entire Qt Framework to our online docs.
This tree includes module docs as subtrees. The essential modules, like Qt Core, Qt GUI, or Qt Quick, are placed on the first level of the tree. The module subtree may include docs for other relevant modules. For example, the Qt Quick subtree contains other Qt Quick related modules:
In the Modules subtree, you can find all the add-ons shipped with Qt Installer.
To be honest, the job is not done yet. Now, we are in a situation where we added a tree to a huge documentation set that never had this kind of navigation. The new navigation tree brought us new capabilities and new challenges, too. Now, we should write the docs with the new navigation in mind.
If you notice that the topic tree can be improved or the content relative to the tree can be optimized, please create a ticket at bugreports.qt.io for the Documentation component and describe in detail how we can improve our navigation or content.
Download the latest release here: www.qt.io/download.
Qt 6.9 is now available, with new features and improvements for application developers and device creators.
Check out all our open positions here and follow us on Instagram to see what it's like to be #QtPeople.
Apr 14, 2025
We're happy to announce the release of version 1.4.0 of the Qt Extension..
Apr 11, 2025
A Heap-buffer-overflow issue in QTextMarkdownImporter has been discovered..
Apr 11, 2025
We are happy to announce the release of Qt Creator 16.0.1! We fixed a..
These are great news!
This is great indeed! QtConcurrent in Qt5 is a good improvement on what's available in C++ and this improves it even further.
Seems very similar https://qtpromise.netlify.app/qtpromise/getting-started.html Making a promise from signal is very useful
Another feature that AsyncFuture has that this implementation is lacking is a way to combine multiple QFutures into one future. For example:
QFuture<int> futureFunc1 = QtConcurrent::run(func1);
QFuture<int> futureFunc2 = QtConcurrent::run(func2);
QFuture<void> futureSignal = QtFuture::connect(button, &QButton::onClicked);
//Combine multiple futures and sync when all of them are finished
QFuture<void> finalFuture = QtFuture::combine({futureFunc1, futureFunc2, futureSignal});
finalFuture.then([futureFunc1, futureFunce2](){ qDebug() << "Results func1:" << futureFunc1.result() << "Result func2:" << futureFunc2.result();});
The current implementation doesn't allow for parallel pipelines to be merged into one QFuture.
Or is this supported?
You're right, it's not supported at the moment. Support for combining multiple futures is also one of the things we can consider adding in future.
I added a bug report here: https://bugreports.qt.io/browse/QTBUG-86728
Any plans for a QCoroutine? :)
No plans for it yet :)
This looks really nice and is well thought out. I've been using AsyncFuture library for a while now and it filled in missing QFuture functionality for Qt5. Couple questions since the Qt6 snapshot documentation doesn't appear to have this new API published:
Can you dynamically chain QFuture? QFuture future = QtConcurrent::task(doSomething) QFuture chainFuture; if(...) { chainFuture = future.then(func1); } else { chainFuture = future.then(func2); } chainFuture.then(finalFunc);
It looks like QFuture isn't templated anymore. Does it still support a list of results? I always thought this was a bit confusing. I guess the new QFuture api isn't compatible with the Qt5 line?
Can you set QFuture (or QPromise) with a completed value. Surprisingly this is very useful. Sometimes you know the value and don't need to reprocess.
Can the .then() statements return QFuture? For example if you have QtConncurrent::mapped() run inside of a .then(QtFuture::Launch::Async). This is something I do a lot in AsyncFuture.
Thank you for the feedback! I fixed the link to documentation snapshots, it was pointing to a wrong version before. And QFuture docs can be found here.
Regarding to your questions:
Yes, your example is completely valid.
QFuture is actually still templated and is entirely compatible with QFuture in Qt 5. And it still supports multiple results, because that's useful with QtConcurrent and in other scenarios, for example, progress reporting, etc.
Unfortunately there is no way of creating a completed QFuture/QPromise yet, but I agree with you, that could be very useful. Will consider implementing it in the upcoming releases.
If the callable passed to .then() returns a QFuture, then the return type of .then() will be QFuture<QFuture<T>>, i.e. no unwrapping is implemented yet. But again, that's also something we'll consider adding :)
Awesome! Thanks for the quick feedback.
I've made bug reports for 3. https://bugreports.qt.io/browse/QTBUG-86724 4. https://bugreports.qt.io/browse/QTBUG-86725
I didn't really study all these old and new APIs, BUT as a Qt user I honestly don't get all the complexities. Can't we just a have a Promise object like in Javascript? I don't understand why QFuture exists in the first place...These APIs look more complicated than signals connected to lambdas so they defeat their own purpose.
I understand this is about multithreading. The confusione arises from talking about "asynchronous" instead of "multithreaded" . Multithreading is 1% of asynchronous use cases. It's needed only for heavy number crunching, not for network requests as in this post examples. What is really missing is a very simple QPromise class, very much like Javascript's. Not a multithreaded one. A function returning a QPromise could be used like this:
myPromiseFunction(myArgs) .then([](auto &result) { // do something with result }).error([](auto &e) { // handler error });
I'm not familiar with Javascript's Promise, but don't see how the separation of producer (i.e. QPromise) and consumer (i.e. QFuture) interfaces makes things complex. The idea is that you can have one producer, and multiple consumers (possibly in different threads) independent from it. Many libraries have this separation (including STL, boost, etc.)
This is not only about multithreading, the new functionality is useful for any asynchronous computation. I think, the example with network request demonstrates that.
Well, you can write exactly the same example with a function returning a QFuture, I don't see what's the problem.
Hey Sona, thanks for the work, it looks very promising! (pun intended). In your examples, there is an 'onFailed' handler, does it 'consume' the rejection or rejects the promises up the chain as well? In Simon Brunel's QtPromise implementation there is a 'tapFail' that can be injected into the promise chain to make an action on promise rejection, but the rejection will be passed further.I'm a bit worried though that you are haven't taken a look at JavaScript's promises. Asynchronous programming in JavaScript, C#, and Scala are kind of state of the art, so I think you should consider reviewing those approaches to take the best bits into Qt. Additionally, if someone who is familiar with those technologies starts with Qt, they would recognize similar patterns and techniques, so it is definitely worth looking at.
Thanks for the feedback.
Yes,
onFailed()
'consumes' the rejection, i.e. if you havefuture.then(func1).then(func2).onFailed(...).then(func3)
: iffunc1
fails with an exception,func2
is skipped and.onFailed()
is called, followed byfunc3
(if.onFailed()
doesn't throw).The intention was to improve the existing QFuture and provide the basic functionality to make it more useful. Considering that many C++ users are probably already familiar with std::future and std::promise, transitioning to QFuture/QPromise should require minimal effort. Of course, that doesn't mean that we won't continue improving the existing functionality. Feel free to submit your suggestions here.
@Sona have a look at this as suggested by Dmitriy. That simple QPromise should be included in Qt6. This is exactly was I talking about and a very high quality implementation too.
I've seen it already, it's indeed a great project, but it's up to the author to decide whether to contribute to Qt or not. We tried to provide our own implementation of a similar functionality, and we are open to suggestions to improve the functionality further.
Well, he tried to contribute, but the Qt people abandoned the discussion at some point: https://bugreports.qt.io/browse/QTBUG-80908 That's all fair of course, but implying that the author decided not to contribute this to Qt6 is a bit of a stretch..
Hey Flavio, you should try Simon Brunel's implementation of Promise/A+: https://github.com/simonbrunel/qtpromise I've used it in a couple of projects and I must say I'd prefer it over the implementation in Qt 6. Exactly for the reason you mentioned: it's easier and is based on a specification. So anybody who has ever used promises in JavaScript would find their way with Simon's QtPromise
Thanks, interesting. This is what I meant. But I think such a core feature has to be provided by Qt in order to be usable in the long term. Qt's API should make use of these simple promises. Then we can start using them in our own code. Alas they are over engineering it.
I am too lazy to look in the implementation but I wonder how do you ensure that continuation of the future is called in the same thread as the function was called. From the higher level point of view, there could be a race - function can exit before continuation is added. Is the thread somehow reserved until all futures leave scope?
No, the thread is not reserved. If continuation is attached after the parent has already finished, it will run in the thread that owns the parent future. I might consider adding another version of .then() which takes a specific QThread*as parameter, to give more control in such cases (which may be useful for other scenarios as well).
Then the doc should be updated, it says > When the asynchronous computation represented by this future finishes, function will be invoked in the same thread in which this future has been running which is not always true=) Maybe it makes sense to use Inherit launch policy for the Function overload [0]? It that case, if future was async, it will be (synchronously) re-scheduled in the pool?
[0] https://github.com/qt/qtbase/blob/dev/src/corelib/thread/qfuture.h#L350
You're right, I'll update the docs :)
In case of Inherit policy, if the parent has been using Async, the continuation will be launched in a new thread (QThreadPool may decide to re-use the parent's thread, but it's not guaranteed). Spawning a new thread for each continuation may not be what the user always wants, so I don't think making it default is a good idea.
Can the mentioned "custom thread pool" have a custom QThread::Priority too?
No, passing a QThread::Priority is not supported.
Looks similar to QtPromise project, nice one. Any plans to add support for context tracking, something like discussed here:
https://github.com/simonbrunel/qtpromise/issues/35
?
Thanks for the feedback. Ability to specify a context seems to be useful, created this.
It definitely would sound cool if coroutines didn't exist. But considering they will soon get full compiler support in Qt's supported compilers, likely soon after Qt 6 is released, I feel like these improvements will become obsolete some months after being released. Coroutines will make asynchronous code way more concise than any imaginable implementation of promises or futures.
I hope the improvements on futures and promises will not impede the efforts for first class Qt support on coroutines - because personally, that's what I will care about in the near future.