<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>pontaoski &amp;mdash; Janet&#39;s Shenanigans</title>
    <link>https://blog.blackquill.cc/tag:pontaoski</link>
    <description></description>
    <pubDate>Mon, 27 Apr 2026 03:22:36 +0000</pubDate>
    <item>
      <title>C++ Coroutines Three: More Than Asynchrony</title>
      <link>https://blog.blackquill.cc/c-coroutines-three-more-than-asynchrony</link>
      <description>&lt;![CDATA[If you haven&#39;t read my previous blogposts on C++ coroutines, I would recommend doing so.&#xA;&#xA;This post isn&#39;t an explanation of implementing something, as much as it is an explanation of something cool you can do in C++ using coroutines. Warning: this is very esoteric from a C++ perspective, and you&#39;re probably going to have problems understanding this post without knowing what algebraic effects are from other languages (mostly research ones), despite my best attempts to explain them.&#xA;&#xA;In short, you can implement a rudimentary version of algebraic effects using C++ coroutines.&#xA;&#xA;But what is an algebraic effect?&#xA;&#xA;The simplest way to describe them is &#34;resumable exceptions that can return a value&#34;.&#xA;&#xA;Koka explains it well with an example:&#xA;&#xA;effect aska {&#xA;  control ask() : a&#xA;}&#xA;&#xA;This defines a generic effect askT with an operation ask that returns a value of type T.&#xA;&#xA;If a function wants to use this effect, it has to declare that it does, much in the same way that some languages require you to declare that your function can throw an exception.&#xA;&#xA;fun ask-and-add-twice() : askint int {&#xA;    return ask() + ask()&#xA;}&#xA;&#xA;When you call this function, the Koka compiler checks that you handle askint somewhere in enclosing scopes, the same way that some languages check that your exceptions are being caught in a try/catch block.&#xA;&#xA;Defining a handler for an effect in Koka looks like this:&#xA;&#xA;fun ask-random() : random int {&#xA;  with control ask(){ resume(random-int()) }&#xA;  add-twice()&#xA;}&#xA;&#xA;fun ask-const() : int {&#xA;  with control ask(){ resume(21) }&#xA;  add-twice()&#xA;}&#xA;&#xA;So what does this have to do w/ C++ and coroutines?&#xA;&#xA;C++ coroutines allow you to pause a function, and resume it, optionally passing in a value. This is the same thing that algebraic effects do: pause a function, and resume it, optionally passing in a value.&#xA;&#xA;As a result, you can implement much of the functionality of algebraic effects in C++ using coroutines.&#xA;&#xA;This is an example snippet of Crouton&#39;s rudimentary implementation of algebraic effects:&#xA;&#xA;using Log = EffectVoidFunstd::function&lt;void(QString)  ;&#xA;&#xA;Effectvoid contextDependentLogging() {&#xA;    perform Log(&#34;hi&#34;);&#xA;&#xA;    co_return;&#xA;}&#xA;&#xA;void log() {&#xA;    {&#xA;        auto handler = Log::handler( -  int {&#xA;            qDebug() &lt;&lt; it;&#xA;        });&#xA;&#xA;        contextDependentLogging();&#xA;    }&#xA;    {&#xA;        auto handler = Log::handler( -  int {&#xA;            qWarning() &lt;&lt; it;&#xA;        });&#xA;&#xA;        contextDependentLogging();&#xA;    }&#xA;}&#xA;&#xA;Algebraic effects are powerful in that they let your functions generic over behaviour, much in the same way that templates allow functions to be generic over types.&#xA;&#xA;For example, say you&#39;re authoring a Matrix client. You can define an effect fetch that GETs/POSTs a URL. Without touching your code that uses fetch, you can transparently replace the handler for fetch in different parts of your application. Your live application could use a handler that uses the actual internet, while unit tests could use a handler that returns dummy data. Compared to #ifdef-ing different implementations, this allows different parts of an application to use different handlers at runtime, and allows library users to provide their own handlers without needing to modify the library.&#xA;&#xA;There&#39;s a lot of stuff you can do with algebraic effects, and this only scratches the tip of the iceberg.&#xA;&#xA;That&#39;s all for this blog post. Stay tuned for more C++-related shenanigans.&#xA;&#xA;Contact Me&#xA;&#xA;If you didn&#39;t understand anything here, please feel free to come to me and ask for clarification. This blog post is probably particularly confusing since it&#39;s deep in the realm of programming language geekery in the same way monads are.&#xA;&#xA;Or, want to talk to me about other coroutine stuff I haven&#39;t discussed in these blog posts (or anything else you might want to talk about)?&#xA;&#xA;Contact me here:&#xA;&#xA;Telegram: https://t.me/pontaoski&#xA;Matrix: #pontaoski:tchncs.de (prefer unencrypted DMs)&#xA;&#xA;Tags: #libre&#xA;&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>If you haven&#39;t read my previous blogposts on C++ coroutines, I would recommend doing so.</p>

<p>This post isn&#39;t an explanation of implementing something, as much as it is an explanation of something cool you can do in C++ using coroutines. Warning: this is very esoteric from a C++ perspective, and you&#39;re probably going to have problems understanding this post without knowing what algebraic effects are from other languages (mostly research ones), despite my best attempts to explain them.</p>

<p>In short, you can implement a rudimentary version of algebraic effects using C++ coroutines.</p>

<p>But what is an algebraic effect?</p>

<p>The simplest way to describe them is “resumable exceptions that can return a value”.</p>

<p><a href="https://koka-lang.github.io/koka/doc/book.html" rel="nofollow">Koka</a> explains it well with an example:</p>

<pre><code class="language-koka">effect ask&lt;a&gt; {
  control ask() : a
}
</code></pre>

<p>This defines a generic effect <code>ask&lt;T&gt;</code> with an operation <code>ask</code> that returns a value of type <code>T</code>.</p>

<p>If a function wants to use this effect, it has to declare that it does, much in the same way that some languages require you to declare that your function can throw an exception.</p>

<pre><code class="language-koka">fun ask-and-add-twice() : ask&lt;int&gt; int {
    return ask() + ask()
}
</code></pre>

<p>When you call this function, the Koka compiler checks that you handle ask somewhere in enclosing scopes, the same way that some languages check that your exceptions are being caught in a <code>try</code>/<code>catch</code> block.</p>

<p>Defining a handler for an effect in Koka looks like this:</p>

<pre><code class="language-koka">fun ask-random() : random int {
  with control ask(){ resume(random-int()) }
  add-twice()
}

fun ask-const() : int {
  with control ask(){ resume(21) }
  add-twice()
}
</code></pre>

<p>So what does this have to do w/ C++ and coroutines?</p>

<p>C++ coroutines allow you to pause a function, and resume it, optionally passing in a value. This is the same thing that algebraic effects do: pause a function, and resume it, optionally passing in a value.</p>

<p>As a result, you can implement much of the functionality of algebraic effects in C++ using coroutines.</p>

<p>This is an example snippet of <a href="https://invent.kde.org/cblack/croutons" rel="nofollow">Crouton&#39;s rudimentary implementation of algebraic effects</a>:</p>

<pre><code class="language-c++">using Log = EffectVoidFun&lt;std::function&lt;void(QString)&gt;&gt;;

Effect&lt;void&gt; contextDependentLogging() {
    perform Log(&#34;hi&#34;);

    co_return;
}

void log() {
    {
        auto handler = Log::handler([](const QString&amp; it) -&gt; int {
            qDebug() &lt;&lt; it;
        });

        contextDependentLogging();
    }
    {
        auto handler = Log::handler([](const QString&amp; it) -&gt; int {
            qWarning() &lt;&lt; it;
        });

        contextDependentLogging();
    }
}
</code></pre>

<p>Algebraic effects are powerful in that they let your functions generic over behaviour, much in the same way that templates allow functions to be generic over types.</p>

<p>For example, say you&#39;re authoring a Matrix client. You can define an effect <code>fetch</code> that GETs/POSTs a URL. Without touching your code that uses <code>fetch</code>, you can transparently replace the handler for <code>fetch</code> in different parts of your application. Your live application could use a handler that uses the actual internet, while unit tests could use a handler that returns dummy data. Compared to <a href="https://blog.blackquill.cc/tag:ifdef" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ifdef</span></a>-ing different implementations, this allows different parts of an application to use different handlers at runtime, and allows library users to provide their own handlers without needing to modify the library.</p>

<p>There&#39;s a lot of stuff you can do with algebraic effects, and this only scratches the tip of the iceberg.</p>

<p>That&#39;s all for this blog post. Stay tuned for more C++-related shenanigans.</p>

<h2 id="contact-me">Contact Me</h2>

<p>If you didn&#39;t understand anything here, please feel free to come to me and ask for clarification. This blog post is probably particularly confusing since it&#39;s deep in the realm of programming language geekery in the same way monads are.</p>

<p>Or, want to talk to me about other coroutine stuff I haven&#39;t discussed in these blog posts (or anything else you might want to talk about)?</p>

<p>Contact me here:</p>

<p>Telegram: <a href="https://t.me/pontaoski" rel="nofollow">https://t.me/pontaoski</a>
Matrix: <a href="https://blog.blackquill.cc/tag:pontaoski" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">pontaoski</span></a>:tchncs.de (prefer unencrypted DMs)</p>

<p>Tags: <a href="https://blog.blackquill.cc/tag:libre" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">libre</span></a></p>
]]></content:encoded>
      <guid>https://blog.blackquill.cc/c-coroutines-three-more-than-asynchrony</guid>
      <pubDate>Tue, 22 Jun 2021 05:12:15 +0000</pubDate>
    </item>
    <item>
      <title>C++ Coroutines Two: Electric Boogaloo: co_await a QNetworkReply*</title>
      <link>https://blog.blackquill.cc/c-coroutines-two-electric-boogaloo-co_await-a-qnetworkreply</link>
      <description>&lt;![CDATA[If you haven&#39;t read my previous blog post on coroutines in C++, you want to do that before reading this blog post.&#xA;&#xA;In the last blog post, I explained how to construct an awaitable Future type.&#xA;&#xA;If you&#39;ve been tinkering with coroutines, you may have tried the following thing to allow awaiting on a pointer type:&#xA;&#xA;auto operator await(QNetworkReply it) {&#xA;    // ...&#xA;}&#xA;&#xA;As far as the C++ compiler is concerned, this ain&#39;t kosher, because you&#39;re trying to define an operator for a primitive type (a pointer). Your compiler will probably tell you that this needs to be done on a class or enum type.&#xA;&#xA;But that leaves the question of &#34;how do I make a QNetworkReply coawaitable if I can&#39;t define coawait on a pointer type?&#34; It is possible.&#xA;&#xA;Your promisetype object has more jobs than what I covered in the last blog post. One of them is to potentially provide an awaittransform function.&#xA;&#xA;An awaittransform function essentially &#34;preprocesses&#34; any values being coawaited before the compiler attempts to look for a coawait implementation.&#xA;&#xA;In code, if awaittransform is defined on a promisetype, any coawait that looks like this:&#xA;&#xA;auto response = coawait pendingValue;&#xA;&#xA;will actually become:&#xA;&#xA;auto response = coawait awaittransform(pendingValue);&#xA;&#xA;This is how we coawait a type you can&#39;t provide an operator coawait for: transform it into a type you can.&#xA;&#xA;To integrate a QNetworkReply into our coroutine types from before, this means we need to make an awaittransform function that takes a QNetworkReply and return a future. This is fairly simple.&#xA;&#xA;auto awaittransform(QNetworkReply* it) {&#xA;    auto future = Future();&#xA;&#xA;    QObject::connect(it, &amp;QNetworkReply::finished, it, future, it {&#xA;        if (it-  error() == QNetworkReply::NoError) {&#xA;            future.succeed(it);&#xA;        } else {&#xA;            future.fail(it);&#xA;        }&#xA;    });&#xA;&#xA;    return future;&#xA;}&#xA;&#xA;Make a future, mark as success if the reply succeeds, mark as failure if it doesn&#39;t succeed. Easy peasy.&#xA;&#xA;Plonk this function in your promisetype from before.&#xA;&#xA;This now allows you to do this:&#xA;&#xA;Future fetch(QString url) {&#xA;    auto response = coawait nam.get(url);&#xA;    if (response.error() != QNetworkReply::NoError) {&#xA;        coreturn response.readAll();&#xA;    }&#xA;    coreturn false;&#xA;}&#xA;&#xA;You can implement an awaittransform for any input you like, and return anything you like, as long as you can co_await it.&#xA;&#xA;The full code for this blog post can be found in a single-file format at https://invent.kde.org/-/snippets/1716. Compile with C++20 and -fcoroutines-ts -stdlib=libc++ for clang, and -fcoroutines for gcc.&#xA;&#xA;A full library built on the style of coroutines introduced here (with type safe template variants) + other goodies for asynchronous Qt is available at https://invent.kde.org/cblack/croutons.&#xA;&#xA;That&#39;s all for this blog post. Stay tuned for more C++-related shenanigans.&#xA;&#xA;Contact Me&#xA;&#xA;If you didn&#39;t understand anything here, please feel free to come to me and ask for clarification.&#xA;&#xA;Or, want to talk to me about other coroutine stuff I haven&#39;t discussed in these blog posts (or anything else you might want to talk about)?&#xA;&#xA;Contact me here:&#xA;&#xA;Telegram: https://t.me/pontaoski&#xA;Matrix: #pontaoski:tchncs.de (prefer unencrypted DMs)&#xA;&#xA;Tags: #libre]]&gt;</description>
      <content:encoded><![CDATA[<p>If you haven&#39;t read my <a href="https://blog.blackquill.cc/c-coroutines-or-why-are-the-templates-failing-aaaaaaaaaaaa" rel="nofollow">previous blog post on coroutines in C++</a>, you want to do that before reading this blog post.</p>

<p>In the last blog post, I explained how to construct an awaitable Future type.</p>

<p>If you&#39;ve been tinkering with coroutines, you may have tried the following thing to allow awaiting on a pointer type:</p>

<pre><code class="language-c++">auto operator await(QNetworkReply* it) {
    // ...
}
</code></pre>

<p>As far as the C++ compiler is concerned, this ain&#39;t kosher, because you&#39;re trying to define an operator for a primitive type (a pointer). Your compiler will probably tell you that this needs to be done on a class or enum type.</p>

<p>But that leaves the question of “how do I make a QNetworkReply* <code>co_await</code>able if I can&#39;t define <code>co_await</code> on a pointer type?” It is possible.</p>

<p>Your <code>promise_type</code> object has more jobs than what I covered in the last blog post. One of them is to potentially provide an <code>await_transform</code> function.</p>

<p>An <code>await_transform</code> function essentially “preprocesses” any values being <code>co_await</code>ed before the compiler attempts to look for a <code>co_await</code> implementation.</p>

<p>In code, if <code>await_transform</code> is defined on a <code>promise_type</code>, any <code>co_await</code> that looks like this:</p>

<pre><code class="language-c++">auto response = co_await pendingValue;
</code></pre>

<p>will actually become:</p>

<pre><code class="language-c++">auto response = co_await await_transform(pendingValue);
</code></pre>

<p>This is how we <code>co_await</code> a type you can&#39;t provide an <code>operator co_await</code> for: transform it into a type you can.</p>

<p>To integrate a QNetworkReply* into our coroutine types from before, this means we need to make an <code>await_transform</code> function that takes a <code>QNetworkReply*</code> and return a future. This is fairly simple.</p>

<pre><code class="language-c++">auto await_transform(QNetworkReply* it) {
    auto future = Future();

    QObject::connect(it, &amp;QNetworkReply::finished, it, [future, it]() {
        if (it-&gt;error() == QNetworkReply::NoError) {
            future.succeed(it);
        } else {
            future.fail(it);
        }
    });

    return future;
}
</code></pre>

<p>Make a future, mark as success if the reply succeeds, mark as failure if it doesn&#39;t succeed. Easy peasy.</p>

<p>Plonk this function in your <code>promise_type</code> from before.</p>

<p>This now allows you to do this:</p>

<pre><code class="language-c++">Future fetch(QString url) {
    auto response = co_await nam.get(url);
    if (response.error() != QNetworkReply::NoError) {
        co_return response.readAll();
    }
    co_return false;
}
</code></pre>

<p>You can implement an <code>await_transform</code> for any input you like, and return anything you like, as long as you can <code>co_await</code> it.</p>

<p>The full code for this blog post can be found in a single-file format at <a href="https://invent.kde.org/-/snippets/1716" rel="nofollow">https://invent.kde.org/-/snippets/1716</a>. Compile with C++20 and <code>-fcoroutines-ts -stdlib=libc++</code> for clang, and <code>-fcoroutines</code> for gcc.</p>

<p>A full library built on the style of coroutines introduced here (with type safe template variants) + other goodies for asynchronous Qt is available at <a href="https://invent.kde.org/cblack/croutons" rel="nofollow">https://invent.kde.org/cblack/croutons</a>.</p>

<p>That&#39;s all for this blog post. Stay tuned for more C++-related shenanigans.</p>

<h2 id="contact-me">Contact Me</h2>

<p>If you didn&#39;t understand anything here, please feel free to come to me and ask for clarification.</p>

<p>Or, want to talk to me about other coroutine stuff I haven&#39;t discussed in these blog posts (or anything else you might want to talk about)?</p>

<p>Contact me here:</p>

<p>Telegram: <a href="https://t.me/pontaoski" rel="nofollow">https://t.me/pontaoski</a>
Matrix: <a href="https://blog.blackquill.cc/tag:pontaoski" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">pontaoski</span></a>:tchncs.de (prefer unencrypted DMs)</p>

<p>Tags: <a href="https://blog.blackquill.cc/tag:libre" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">libre</span></a></p>
]]></content:encoded>
      <guid>https://blog.blackquill.cc/c-coroutines-two-electric-boogaloo-co_await-a-qnetworkreply</guid>
      <pubDate>Wed, 16 Jun 2021 17:39:00 +0000</pubDate>
    </item>
    <item>
      <title>C++ Coroutines, or &#34;why are the templates failing aaaaaAAAAAAA&#34;</title>
      <link>https://blog.blackquill.cc/c-coroutines-or-why-are-the-templates-failing-aaaaaaaaaaaa</link>
      <description>&lt;![CDATA[Qt&#39;s networking code has always been one of its more obtuse parts, requiring using signals for something that didn&#39;t quite seem right for them. A linear flow of code would become a jumbled mess of member functions and signal connections.&#xA;&#xA;When developing Challah&#39;s netcode, I quickly realised this wasn&#39;t going to suffice for the large amount of it I was going to be writing. Thus begins my journey through signal hell, arriving at many bumps before I discovered that integrating Qt&#39;s networking stuff with coroutines is possible.&#xA;&#xA;Stop Zero&#xA;&#xA;If you&#39;re just here to see some cool coroutine code, you can look at https://invent.kde.org/-/snippets/1711 for an single-file version of the tutorial in this blog-post, with a coroutine function already made and ready for you to play with. If you want something more full-fledged, look at https://invent.kde.org/cblack/coroutines.&#xA;&#xA;But if you want to know what&#39;s actually going on behind the scenes, continue reading.&#xA;&#xA;Stop One: Don&#39;t Do This&#xA;&#xA;Approach one that I took to get out of signal hell was a simple while loop:&#xA;&#xA;while (!reply-  isFinished()) {&#xA;    QCoreApplication::processEvents();&#xA;}&#xA;&#xA;This is a bad idea. Strange graphical glitches, bugs, crashes, etc. lie behind this innocuous code. Don&#39;t do it. Forcibly spinning the event loop in a lot of places causes a lot of bugs.&#xA;&#xA;Step Two: Callback Hell&#xA;&#xA;So, what do you do if you want to write somewhat linear code without doing that? Callbacks.&#xA;&#xA;QObject::connect(val, &amp;QNetworkReply::finished, val, callback {&#xA;    if (val-  error() != QNetworkReply::NoError) {&#xA;        val-  deleteLater();&#xA;        callback({QStringLiteral(&#34;network failure(%1): %2&#34;).arg(val-  error()).arg(val-  errorString())});&#xA;        return;&#xA;    }&#xA;    &#xA;    auto response = val-  readAll();&#xA;    &#xA;    protocol::chat::v1::CreateGuildResponse ret;&#xA;    if (!ret.ParseFromArray(response.constData(), response.length())) {&#xA;        val-  deleteLater();&#xA;        callback({QStringLiteral(&#34;error parsing response into protobuf&#34;)});&#xA;        return;&#xA;    }&#xA;    &#xA;    val-  deleteLater();&#xA;    callback({ret});&#xA;    return;&#xA;});&#xA;&#xA;Every time I had to call into the netcode, I would have to provide a std::functionvoid(std::variant&lt;Result,Error)  . It&#39;s passable for a single call, but chaining them quickly violates &#34;happy path sticks to the left&#34;, making you wonder if you&#39;re actually writing Python with how far indented your code is.&#xA;&#xA;c-  call(c {&#xA;  c-  call(c {&#xA;    c-  call(c {&#xA;      c-  call(c {&#xA;        c-  call(c {&#xA;        });&#xA;      });&#xA;    });&#xA;  });&#xA;});&#xA;&#xA;Not good.&#xA;&#xA;Step Three: Out of the Inferno, Into the Frying Pan&#xA;&#xA;await/async as a mechanic in languages generally reduces the amount of callback hell you face by sugaring it for you. For example, in JS, this:&#xA;&#xA;return fetch().then((it) =  {&#xA;    return it.text&#xA;})&#xA;&#xA;is equivalent to this:&#xA;&#xA;return await fetch().text&#xA;&#xA;Both of these return the exact same thing to the caller, but one is much easier to deal with when chained.&#xA;&#xA;For a while, C++ didn&#39;t have this. Of course, with C++20, coroutines with coawait &amp; company are now available in most compilers.&#xA;&#xA;Diversion: That Asterisk&#xA;&#xA;Coroutines are technically available in most compilers, but you&#39;re going to have to do a lot of compiler-specific dances in both your code and the build system in order to pass the correct flags to enable coroutines.&#xA;&#xA;I use this snippet to handle clang &amp; gcc:&#xA;if defined(clang)&#xA;&#xA;include experimental/coroutine&#xA;namespace ns = std::experimental;&#xA;&#xA;elif defined(GNUC)&#xA;&#xA;include coroutine&#xA;namespace ns = std;&#xA;&#xA;endif&#xA;&#xA;where ns is aliased to the namespace containing coroutine-related stuff. Also note that clang will probably fail to compile stuff due to experimental/coroutine being part of libc++ while the rest of your system probably uses gcc&#39;s libstdc++. So, for all intents and purposes, gcc is your only option with coroutines on Linux.&#xA;&#xA;Anyways...&#xA;&#xA;Unhelpful Documentation&#xA;&#xA;When hacking on coroutines, I quickly realised: the available documentation on what they were was both young and immature, as well as unhelpful in what they did have. So, this blog post is going to document them.&#xA;&#xA;Parts of the Coroutine&#xA;&#xA;Coroutines are largely split into two parts: the &#34;promise&#34; and the &#34;awaitable&#34;.&#xA;&#xA;The promise is responsible for handling the &#34;internal&#34; side of any coroutine: it&#39;s what provides the return value, its yield behaviour, handling unhandled exceptions, the &#34;await transformer&#34;, and some other things. All coroutines need to return a type associated with one of these.&#xA;&#xA;The awaitable handles the &#34;external&#34; side of the coroutine being coawaited. One of its first tasks is checking with the outside world whether or not the coroutine needs to suspend. If something is already available, there&#39;s no need to wait on it to become available. If the coroutine does need to wait, the awaitable receives a handle to reactivate it and is responsible for doing so, e.g. when an asynchronous network request completes and its results are available. The awaitable is also responsible for providing the final value returned to the user from coawaiting a coroutine.&#xA;&#xA;As far as stuff that&#39;s directly interacting with coroutines goes, that&#39;s mostly it. However, there&#39;s still one type you need for an end-user API: the type returned by a coroutine, which is what the compiler uses to match your coroutine to a promise type.&#xA;&#xA;SomeType acoroutine() {&#xA;    auto foo = coawait anotherthing();&#xA;    // ...&#xA;} &#xA;&#xA;This SomeType is what I will be calling the &#34;future&#34; or the &#34;task&#34; type, as it&#39;s basically the QFuture of the QPromise (or QFutureInterface to speak in Qt5 parlance).&#xA;&#xA;C++ coroutines are very much &#34;bring your own runtime and types&#34;, and thankfully, that&#39;s what Qt already has, making it perfect for integrating into coroutines.&#xA;&#xA;A QML-friendly future&#xA;&#xA;C++ coroutines are the perfect fix to a long-standing issue in QML: representing asynchronous results in the UI in a manner that being an object property or model data can&#39;t.&#xA;&#xA;So, let&#39;s get to constructing the base of our coroutines, and a type that will be suitable for passing into QML.&#xA;&#xA;For ease of use, we&#39;ll want this done as a copyable QGADGET type with implicitly shared data. This will help us later down the road when we&#39;re passing the future type through lambdas.&#xA;&#xA;(For the sake of simplicity of teaching how coroutines work, I&#39;ll be doing a simple non-template future type that talks in QVariants and doesn&#39;t have success/failure states. If you want to see code with more type safety and success/failure states, you can check out https://invent.kde.org/cblack/coroutines.)&#xA;&#xA;We&#39;ll start by defining our shared data &amp; behaviour.&#xA;&#xA;class Future&#xA;{&#xA;    QGADGET&#xA;&#xA;    struct Shared {&#xA;        QVariant result;&#xA;        std::functionvoid(QVariant) then =  {};&#xA;        bool done = false;&#xA;    };&#xA;    QSharedPointerShared d;&#xA;&#xA;public:&#xA;&#xA;    Future() {&#xA;        d.reset(new Shared);&#xA;    }&#xA;    Future(const Future&amp; other) {&#xA;        this-  d = other.d;&#xA;    }&#xA;};&#xA;&#xA;This gives us a Future that is effectively a blob. First, let&#39;s define getters for done and result, so the outside world can actually tell what the current state of the Future is:&#xA;&#xA;bool settled() const {&#xA;    return d-  done;&#xA;}&#xA;QVariant result() const {&#xA;    return d-  result;&#xA;}&#xA;&#xA;Now we need a way to say that the future is completed and a result is available.&#xA;&#xA;void succeed(const QVariant&amp; value) const {&#xA;    if (d-  done) {&#xA;        return;&#xA;    }&#xA;    d-  done = true;&#xA;    d-  result = value;&#xA;    d-  then(d-  result);&#xA;}&#xA;&#xA;We don&#39;t want to trigger the callback again if we&#39;ve already marked the future as done, so we abort early if we&#39;re already done.&#xA;&#xA;You may notice that this function, despite being a setter semantically, is marked as const. This is mostly for ease of dealing with in lambdas later on.&#xA;&#xA;Now, we need a way to register the callback function in the C++ side of things.&#xA;&#xA;void then(std::functionvoid(QVariant) then) const {&#xA;    d-  then = then;&#xA;&#xA;    if (d-  done) {&#xA;        then(result());&#xA;    }&#xA;}&#xA;&#xA;If the future is already done and you register a callback, you want to call it immediately. This is to handle situations like this:&#xA;&#xA;Future fetch() {&#xA;  if (cache.hasthing()) {&#xA;    Future future;&#xA;    future.succeed(cache.getthing();&#xA;    return future;&#xA;  }&#xA;  // ...&#xA;}&#xA;void main() {&#xA;    fetch().then( {&#xA;    });&#xA;}&#xA;&#xA;If we didn&#39;t invoke the callback in then(), the callback would never be triggered as the future was returned to the caller in an already succeeded status.&#xA;&#xA;Since I promised a QML-friendly future type, we should implement that now.&#xA;&#xA;QINVOKABLE void then(const QJSValue&amp; it) {&#xA;    then(va = it mutable {&#xA;        va.call({va.engine()-  toScriptValue(result)});&#xA;    });&#xA;}&#xA;&#xA;We add a QINVOKABLE overload that takes a QJSValue, as JS functions are represented as QJSValues in C++. We then have a lambda which we pass back into the other then function, taking the QVariant, transforming it into a QJSValue, and calling the JavaScript callback with the variant.&#xA;&#xA;JS usage looks like this:&#xA;&#xA;future.then((it) =  {&#xA;    console.warn(it)&#xA;})&#xA;&#xA;If you&#39;ve been following along, you should now have this class:&#xA;&#xA;class Future&#xA;{&#xA;&#xA;    QGADGET&#xA;&#xA;    struct Shared {&#xA;        QVariant result;&#xA;        std::functionvoid(QVariant) then =  {};&#xA;        bool done = false;&#xA;    };&#xA;    QSharedPointerShared d;&#xA;&#xA;public:&#xA;&#xA;    Future() {&#xA;        d.reset(new Shared);&#xA;    }&#xA;    Future(const FutureBase&amp; other) {&#xA;        this-  d = other.d;&#xA;    }&#xA;&#xA;    bool settled() const {&#xA;        return d-  done;&#xA;    }&#xA;    QVariant result() const {&#xA;        return d-  result;&#xA;    }&#xA;&#xA;    void succeed(const QVariant&amp; value) const {&#xA;        if (d-  done) {&#xA;            return;&#xA;        }&#xA;        d-  done = true;&#xA;        d-  result = value;&#xA;        d-  then(d-  result);&#xA;    }&#xA;&#xA;    void then(std::functionvoid(QVariant) then) const {&#xA;        d-  then = then;&#xA;&#xA;        if (d-  done) {&#xA;            then(result());&#xA;        }&#xA;    }&#xA;    QINVOKABLE void then(const QJSValue&amp; it) {&#xA;        then(va = it mutable {&#xA;            va.call({va.engine()-  toScriptValue(result)});&#xA;        });&#xA;    }&#xA;};&#xA;&#xA;The Backing Promise&#xA;&#xA;Of course, the above class doesn&#39;t make a coroutine. For this, we need to implement the promise type.&#xA;&#xA;For placement options, you have two places where you can put this: inside the future type itself, or outside of the type in an explicit coroutinetraits template specialisation.&#xA;&#xA;The former would look like this:&#xA;&#xA;class Future {&#xA;   // ...&#xA;   struct promisetype {&#xA;   };&#xA;};&#xA;&#xA;While the latter would look like this:&#xA;templatetypename ...Args&#xA;struct ns::coroutinetraitsFuture, Args... {&#xA;    struct promisetype {&#xA;    };&#xA;};&#xA;(where ns is the namespace with the coroutine types, std:: on gcc or std::experimental on clang.)&#xA;&#xA;The latter allows you to implement a promise type for any type, not just one that you have control of the declaration of.&#xA;&#xA;For this blog post, I&#39;ll be going with the latter approach.&#xA;&#xA;struct promisetype {&#xA;};&#xA;&#xA;One of the things we&#39;ll need in our promise type is a member variable to hold the future type.&#xA;&#xA;struct promisetype {&#xA;    Future future;&#xA;};&#xA;&#xA;Of course, the compiler doesn&#39;t know about this member variable, so we need to start implementing the promisetype interface:&#xA;&#xA;struct promisetype {&#xA;    Future future;&#xA;    Future getreturnobject() noexcept {&#xA;        return future;&#xA;    }&#xA;};&#xA;&#xA;T getreturnobject() noexcept is the exact type signature that needs to be implemented. We use noexcept here, as exceptions can cause a double free, and therefore, a crash.&#xA;&#xA;Now, we need to implement two things: initialsuspend() and finalsuspend(). These two functions are called at the start and end of your coroutine, and have to return a coawaitable type. &#xA;&#xA;In an expanded form, initialsuspend and finalsuspend look like this:&#xA;Future yourcoroutine() {&#xA;    coawait promise.initialsuspend();&#xA;    // coroutine body here...&#xA;    coawait promise.finalsuspend();&#xA;}&#xA;&#xA;You could theoretically return anything you want here, but you&#39;ll likely be sticking with ns::suspendnever, which is an awaitable value that resumes execution of the coroutine immediately when coawaited, and what we&#39;ll be using for this blog post.&#xA;&#xA;Add the implementation to your promise type:&#xA;&#xA;ns::suspendnever initialsuspend() const noexcept { return {}; }&#xA;ns::suspendnever finalsuspend() const noexcept { return {}; }&#xA;&#xA;Your promise is responsible for taking care of any values that are coreturned with the returnvalue function.&#xA;&#xA;I recommend having two overloads: const T&amp; (copy value) and T&amp;&amp; (move value).&#xA;&#xA;For our promisetype, the implementation of those will simply look like this:&#xA;&#xA;void returnvalue(const QVariant&amp; value) noexcept&#xA;{&#xA;    future.succeed(value);&#xA;}&#xA;void returnvalue(QVariant &amp;&amp;value) noexcept&#xA;{&#xA;    future.succeed(std::move(value));&#xA;}&#xA;&#xA;If your coroutine was returning something like a std::uniqueptrT, you would need the std::move in order to properly handle it, and thus why I say you should have this overload in your promise type.&#xA;&#xA;With getreturnobject, initialsuspend, finalsuspend, and returnvalue, you only have one remaining function left to implement in your coroutine. It&#39;s quite simple.&#xA;&#xA;void unhandledexception() noexcept {&#xA;&#xA;}&#xA;&#xA;This is what gets called in the catch block of a try/catch block catching exceptions that the coroutine might throw. Use std::currentexception() to access the exception.&#xA;&#xA;For this blog post, we&#39;ll simply be doing QASSERT(&#34;unhandled exception&#34;); in our implementation.&#xA;&#xA;With that, the promise type is complete. It should look something like this:&#xA;&#xA;struct promisetype {&#xA;    Future future;&#xA;&#xA;    Future getreturnobject() noexcept {&#xA;        return future;&#xA;    }&#xA;&#xA;    ns::suspendnever initialsuspend() const noexcept { return {}; }&#xA;    ns::suspendnever finalsuspend() const noexcept { return {}; }&#xA;&#xA;    void returnvalue(const QVariant&amp; value) noexcept&#xA;    {&#xA;        future.succeed(value);&#xA;    }&#xA;    void returnvalue(QVariant &amp;&amp;value) noexcept&#xA;    {&#xA;        future.succeed(std::move(value));&#xA;    }&#xA;&#xA;    void unhandledexception() noexcept {&#xA;        QASSERT(&#34;unhandled exception&#34;);&#xA;    }&#xA;};&#xA;&#xA;Remember that this needs to be within the Future type itself, or within the appropriate coroutinetraits overload.&#xA;&#xA;The Awaitable&#xA;&#xA;With the Future and promise completed, we don&#39;t have much left to do. We now need to implement operator coawait(Future) in order to allow the Future to be awaited.&#xA;&#xA;Technically, we don&#39;t need the promise type to make a Future awaitable, only the Future and the coawait overload. Implementing a promise type allows your coroutine that&#39;s coawaiting a Future to return another Future.&#xA;&#xA;There&#39;s not really much to the coawait overload, so I&#39;ll just paste an implementation verbatim: &#xA;&#xA;auto operator coawait(Future it) noexcept&#xA;{&#xA;    struct Awaiter {&#xA;        Future future;&#xA;&#xA;        bool awaitready() const noexcept {&#xA;            return future.settled();&#xA;        }&#xA;        void awaitsuspend(ns::coroutinehandle cont) const {&#xA;            future.then(cont mutable {&#xA;                cont();&#xA;            });&#xA;        }&#xA;        QVariant awaitresume() {&#xA;            return future.result();&#xA;        }&#xA;    };&#xA;&#xA;    return Awaiter{ it };&#xA;}&#xA;&#xA;coawait needs to return a type with the following methods:&#xA;&#xA;bool awaitready() const noexcept: This function is called before suspending the coroutine to wait on the awaitable to resolve. If the function returns true, the coroutine continues execution without suspending. If the function returns false, it suspends and waits on the value.&#xA;&#xA;Think back to the example of a function returning an already succeeded future to see why this is useful. If the future already holds a value, there&#39;s no need to waste time suspending the coroutine.&#xA;&#xA;void awaitsuspend(ns::coroutinehandle callback) const: This function is called when the coroutine suspends with a coroutine handle passed in. For all intents and purposes, you can treat it as if it were a std::function holding a callback, except operator () resumes the coroutine instead of calling a function.&#xA;&#xA;You call the coroutinehandle to resume the coroutine when whenever it&#39;s waiting on is ready, e.g. when the future in this example is marked as succeeded. You can connect this to just about anything, e.g. a QTimer::singleShot, a signal, using it as a callback, etc.&#xA;&#xA;T awaitresume() const: This is the value that gets assigned to the result of coawaiting the expression:&#xA;auto it = coawait fetchFromNetwork();&#xA;  // |&#xA;  // ^ this is the value from awaitresume()&#xA;&#xA;Annd with all three types implemented, you now have a QML-friendly future, a promise, and an awaitable.&#xA;&#xA;A Brand New Washing Machine&#xA;&#xA;With your new coroutine, you can do just about anything asynchronously. This is an example function that returns a future that will be fufilled in N miliseconds:&#xA;&#xA;Future timer(int duration) {&#xA;    Future it;&#xA;&#xA;    QTimer::singleShot(duration, it {&#xA;        it.succeed({});&#xA;    });&#xA;&#xA;    return it;&#xA;}&#xA;&#xA;Note that while it returns a Future, it is not a coroutine. It does not coawait. This is a completely normal function that you can call however you desire.&#xA;&#xA;Making a coroutine using this function is easy:&#xA;Future thisIsACoroutine() {&#xA;    coawait timer(2000);&#xA;&#xA;    coreturn {};&#xA;}&#xA;&#xA;Note that this function could not return void. The return type of a coroutine has to have an associated promise type, which void does not.&#xA;&#xA;In a class exposed to QML...&#xA;&#xA;class Singleton : public QObject&#xA;{&#xA;    QOBJECT&#xA;&#xA;public:&#xA;    QINVOKABLE Future foo() {&#xA;        coawait timer(2000);&#xA;&#xA;        coreturn &#34;i was returned by a coroutine&#34;;&#xA;    };&#xA;};&#xA;&#xA;This can be used like so:&#xA;&#xA;Button {&#xA;    anchors.centerIn: parent&#xA;    text: &#34;a coroutine!&#34;&#xA;    onClicked: Singleton.foo().then((val) =  {&#xA;        console.warn(val)&#xA;    })&#xA;}&#xA;&#xA;This will output the following in your console 2 seconds after every time you press this button:&#xA;qml: &#34;i was returned by a coroutine&#34;&#xA;&#xA;The inline code from this blog post can be found in a single-file format at https://invent.kde.org/-/snippets/1711. Compile with C++20 and -fcoroutines-ts -stdlib=libc++ for clang, and -fcoroutines for gcc.&#xA;&#xA;For a basic future+promise+awaitable deal, this is about all you need to know. However, the iceberg gets way deeper than that.&#xA;&#xA;Stay tuned for more blog posts about the eldritch arcana you can pull off with coroutines. Next one will probably be about wrapping already-existing types such as a QNetworkReply in order to make them co_await-able.&#xA;&#xA;You can see more advanced (and arguably useful) code at https://invent.kde.org/cblack/coroutines.&#xA;&#xA;Contact Me&#xA;&#xA;Note that I wrote this blog post at 2 in the morning. If there&#39;s anything that doesn&#39;t make sense, please feel free to come to me and ask for clarification.&#xA;&#xA;Or, want to talk to me about other coroutine stuff I haven&#39;t discussed in this blog post (or anything else you might want to talk about)?&#xA;&#xA;Contact me here:&#xA;&#xA;Telegram: https://t.me/pontaoski&#xA;Matrix: #pontaoski:tchncs.de (prefer unencrypted DMs)&#xA;&#xA;Tags: #libre&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>Qt&#39;s networking code has always been one of its more obtuse parts, requiring using signals for something that didn&#39;t quite seem right for them. A linear flow of code would become a jumbled mess of member functions and signal connections.</p>

<p>When developing <a href="https://github.com/harmony-development/challah" rel="nofollow">Challah</a>&#39;s netcode, I quickly realised this wasn&#39;t going to suffice for the large amount of it I was going to be writing. Thus begins my journey through signal hell, arriving at many bumps before I discovered that integrating Qt&#39;s networking stuff with coroutines is possible.</p>

<h2 id="stop-zero">Stop Zero</h2>

<p>If you&#39;re just here to see some cool coroutine code, you can look at <a href="https://invent.kde.org/-/snippets/1711" rel="nofollow">https://invent.kde.org/-/snippets/1711</a> for an single-file version of the tutorial in this blog-post, with a coroutine function already made and ready for you to play with. If you want something more full-fledged, look at <a href="https://invent.kde.org/cblack/coroutines" rel="nofollow">https://invent.kde.org/cblack/coroutines</a>.</p>

<p>But if you want to know what&#39;s actually going on behind the scenes, continue reading.</p>

<h2 id="stop-one-don-t-do-this">Stop One: Don&#39;t Do This</h2>

<p>Approach one that I took to get out of signal hell was a simple while loop:</p>

<pre><code class="language-c++">while (!reply-&gt;isFinished()) {
    QCoreApplication::processEvents();
}
</code></pre>

<p>This is a bad idea. Strange graphical glitches, bugs, crashes, etc. lie behind this innocuous code. Don&#39;t do it. Forcibly spinning the event loop in a lot of places causes a lot of bugs.</p>

<h2 id="step-two-callback-hell">Step Two: Callback Hell</h2>

<p>So, what do you do if you want to write somewhat linear code without doing that? Callbacks.</p>

<pre><code class="language-c++">QObject::connect(val, &amp;QNetworkReply::finished, [val, callback]() {
    if (val-&gt;error() != QNetworkReply::NoError) {
        val-&gt;deleteLater();
        callback({QStringLiteral(&#34;network failure(%1): %2&#34;).arg(val-&gt;error()).arg(val-&gt;errorString())});
        return;
    }
    
    auto response = val-&gt;readAll();
    
    protocol::chat::v1::CreateGuildResponse ret;
    if (!ret.ParseFromArray(response.constData(), response.length())) {
        val-&gt;deleteLater();
        callback({QStringLiteral(&#34;error parsing response into protobuf&#34;)});
        return;
    }
    
    val-&gt;deleteLater();
    callback({ret});
    return;
});
</code></pre>

<p>Every time I had to call into the netcode, I would have to provide a <code>std::function&lt;void(std::variant&lt;Result,Error&gt;)&gt;</code>. It&#39;s passable for a single call, but chaining them quickly violates “happy path sticks to the left”, making you wonder if you&#39;re actually writing Python with how far indented your code is.</p>

<pre><code>c-&gt;call([c](auto response) {
  c-&gt;call([c](auto response) {
    c-&gt;call([c](auto response) {
      c-&gt;call([c](auto response) {
        c-&gt;call([c](auto response) {
        });
      });
    });
  });
});
</code></pre>

<p>Not good.</p>

<h2 id="step-three-out-of-the-inferno-into-the-frying-pan">Step Three: Out of the Inferno, Into the Frying Pan</h2>

<p>await/async as a mechanic in languages generally reduces the amount of callback hell you face by sugaring it for you. For example, in JS, this:</p>

<pre><code class="language-js">return fetch().then((it) =&gt; {
    return it.text
})
</code></pre>

<p>is equivalent to this:</p>

<pre><code class="language-js">return await fetch().text
</code></pre>

<p>Both of these return the exact same thing to the caller, but one is much easier to deal with when chained.</p>

<p>For a while, C++ didn&#39;t have this. Of course, with C++20, coroutines with co_await &amp; company are now available* in most compilers.</p>

<h3 id="diversion-that-asterisk">Diversion: That Asterisk</h3>

<p>Coroutines are technically available in most compilers, but you&#39;re going to have to do a lot of compiler-specific dances in both your code and the build system in order to pass the correct flags to enable coroutines.</p>

<p>I use this snippet to handle clang &amp; gcc:</p>

<pre><code class="language-c++">#if defined(__clang__)

#include &lt;experimental/coroutine&gt;
namespace ns = std::experimental;

#elif defined(__GNUC__)

#include &lt;coroutine&gt;
namespace ns = std;

#endif
</code></pre>

<p>where ns is aliased to the namespace containing coroutine-related stuff. Also note that clang will probably fail to compile stuff due to experimental/coroutine being part of libc++ while the rest of your system probably uses gcc&#39;s libstdc++. So, for all intents and purposes, gcc is your only option with coroutines on Linux.</p>

<p>Anyways...</p>

<h2 id="unhelpful-documentation">Unhelpful Documentation</h2>

<p>When hacking on coroutines, I quickly realised: the available documentation on what they were was both young and immature, as well as unhelpful in what they did have. So, this blog post is going to document them.</p>

<h2 id="parts-of-the-coroutine">Parts of the Coroutine</h2>

<p>Coroutines are largely split into two parts: the “promise” and the “awaitable”.</p>

<p>The promise is responsible for handling the “internal” side of any coroutine: it&#39;s what provides the return value, its yield behaviour, handling unhandled exceptions, the “await transformer”, and some other things. All coroutines need to return a type associated with one of these.</p>

<p>The awaitable handles the “external” side of the coroutine being co<em>awaited. One of its first tasks is checking with the outside world whether or not the coroutine needs to suspend. If something is already available, there&#39;s no need to wait on it to become available. If the coroutine does need to wait, the awaitable receives a handle to reactivate it and is responsible for doing so, e.g. when an asynchronous network request completes and its results are available. The awaitable is also responsible for providing the final value returned to the user from co</em>awaiting a coroutine.</p>

<p>As far as stuff that&#39;s directly interacting with coroutines goes, that&#39;s mostly it. However, there&#39;s still one type you need for an end-user API: the type returned by a coroutine, which is what the compiler uses to match your coroutine to a promise type.</p>

<pre><code class="language-c++">SomeType a_coroutine() {
    auto foo = co_await another_thing();
    // ...
} 
</code></pre>

<p>This SomeType is what I will be calling the “future” or the “task” type, as it&#39;s basically the QFuture of the QPromise (or QFutureInterface to speak in Qt5 parlance).</p>

<p>C++ coroutines are very much “bring your own runtime and types”, and thankfully, that&#39;s what Qt already has, making it perfect for integrating into coroutines.</p>

<h2 id="a-qml-friendly-future">A QML-friendly future</h2>

<p>C++ coroutines are the perfect fix to a long-standing issue in QML: representing asynchronous results in the UI in a manner that being an object property or model data can&#39;t.</p>

<p>So, let&#39;s get to constructing the base of our coroutines, and a type that will be suitable for passing into QML.</p>

<p>For ease of use, we&#39;ll want this done as a copyable Q_GADGET type with implicitly shared data. This will help us later down the road when we&#39;re passing the future type through lambdas.</p>

<p>(For the sake of simplicity of teaching how coroutines work, I&#39;ll be doing a simple non-template future type that talks in QVariants and doesn&#39;t have success/failure states. If you want to see code with more type safety and success/failure states, you can check out <a href="https://invent.kde.org/cblack/coroutines." rel="nofollow">https://invent.kde.org/cblack/coroutines.</a>)</p>

<p>We&#39;ll start by defining our shared data &amp; behaviour.</p>

<pre><code class="language-c++">class Future
{
    Q_GADGET

    struct Shared {
        QVariant result;
        std::function&lt;void(QVariant)&gt; then = [](QVariant) {};
        bool done = false;
    };
    QSharedPointer&lt;Shared&gt; d;

public:

    Future() {
        d.reset(new Shared);
    }
    Future(const Future&amp; other) {
        this-&gt;d = other.d;
    }
};
</code></pre>

<p>This gives us a Future that is effectively a blob. First, let&#39;s define getters for done and result, so the outside world can actually tell what the current state of the Future is:</p>

<pre><code class="language-c++">bool settled() const {
    return d-&gt;done;
}
QVariant result() const {
    return d-&gt;result;
}
</code></pre>

<p>Now we need a way to say that the future is completed and a result is available.</p>

<pre><code class="language-c++">void succeed(const QVariant&amp; value) const {
    if (d-&gt;done) {
        return;
    }
    d-&gt;done = true;
    d-&gt;result = value;
    d-&gt;then(d-&gt;result);
}
</code></pre>

<p>We don&#39;t want to trigger the callback again if we&#39;ve already marked the future as done, so we abort early if we&#39;re already done.</p>

<p>You may notice that this function, despite being a setter semantically, is marked as const. This is mostly for ease of dealing with in lambdas later on.</p>

<p>Now, we need a way to register the callback function in the C++ side of things.</p>

<pre><code class="language-c++">void then(std::function&lt;void(QVariant)&gt; then) const {
    d-&gt;then = then;

    if (d-&gt;done) {
        then(result());
    }
}
</code></pre>

<p>If the future is already done and you register a callback, you want to call it immediately. This is to handle situations like this:</p>

<pre><code class="language-c++">Future fetch() {
  if (cache.has_thing()) {
    Future future;
    future.succeed(cache.get_thing();
    return future;
  }
  // ...
}
void main() {
    fetch().then([](QVariant) {
    });
}
</code></pre>

<p>If we didn&#39;t invoke the callback in then(), the callback would never be triggered as the future was returned to the caller in an already succeeded status.</p>

<p>Since I promised a QML-friendly future type, we should implement that now.</p>

<pre><code class="language-c++">Q_INVOKABLE void then(const QJSValue&amp; it) {
    then([va = it](QVariant result) mutable {
        va.call({va.engine()-&gt;toScriptValue(result)});
    });
}
</code></pre>

<p>We add a Q_INVOKABLE overload that takes a QJSValue, as JS functions are represented as QJSValues in C++. We then have a lambda which we pass back into the other <code>then</code> function, taking the QVariant, transforming it into a QJSValue, and calling the JavaScript callback with the variant.</p>

<p>JS usage looks like this:</p>

<pre><code>future.then((it) =&gt; {
    console.warn(it)
})
</code></pre>

<p>If you&#39;ve been following along, you should now have this class:</p>

<pre><code class="language-c++">class Future
{

    Q_GADGET

    struct Shared {
        QVariant result;
        std::function&lt;void(QVariant)&gt; then = [](QVariant) {};
        bool done = false;
    };
    QSharedPointer&lt;Shared&gt; d;

public:

    Future() {
        d.reset(new Shared);
    }
    Future(const FutureBase&amp; other) {
        this-&gt;d = other.d;
    }

    bool settled() const {
        return d-&gt;done;
    }
    QVariant result() const {
        return d-&gt;result;
    }

    void succeed(const QVariant&amp; value) const {
        if (d-&gt;done) {
            return;
        }
        d-&gt;done = true;
        d-&gt;result = value;
        d-&gt;then(d-&gt;result);
    }

    void then(std::function&lt;void(QVariant)&gt; then) const {
        d-&gt;then = then;

        if (d-&gt;done) {
            then(result());
        }
    }
    Q_INVOKABLE void then(const QJSValue&amp; it) {
        then([va = it](QVariant result) mutable {
            va.call({va.engine()-&gt;toScriptValue(result)});
        });
    }
};
</code></pre>

<h2 id="the-backing-promise">The Backing Promise</h2>

<p>Of course, the above class doesn&#39;t make a coroutine. For this, we need to implement the promise type.</p>

<p>For placement options, you have two places where you can put this: inside the future type itself, or outside of the type in an explicit coroutine_traits template specialisation.</p>

<p>The former would look like this:</p>

<pre><code class="language-c++">class Future {
   // ...
   struct promise_type {
   };
};
</code></pre>

<p>While the latter would look like this:</p>

<pre><code class="language-c++">template&lt;typename ...Args&gt;
struct ns::coroutine_traits&lt;Future, Args...&gt; {
    struct promise_type {
    };
};
</code></pre>

<p>(where ns is the namespace with the coroutine types, std:: on gcc or std::experimental on clang.)</p>

<p>The latter allows you to implement a promise type for any type, not just one that you have control of the declaration of.</p>

<p>For this blog post, I&#39;ll be going with the latter approach.</p>

<pre><code class="language-c++">struct promise_type {
};
</code></pre>

<p>One of the things we&#39;ll need in our promise type is a member variable to hold the future type.</p>

<pre><code class="language-c++">struct promise_type {
    Future _future;
};
</code></pre>

<p>Of course, the compiler doesn&#39;t know about this member variable, so we need to start implementing the promise_type interface:</p>

<pre><code class="language-c++">struct promise_type {
    Future _future;
    Future get_return_object() noexcept {
        return _future;
    }
};
</code></pre>

<p><code>T get_return_object() noexcept</code> is the exact type signature that needs to be implemented. We use <code>noexcept</code> here, as exceptions can cause a double free, and therefore, a crash.</p>

<p>Now, we need to implement two things: <code>initial_suspend()</code> and <code>final_suspend()</code>. These two functions are called at the start and end of your coroutine, and have to return a co_awaitable type.</p>

<p>In an expanded form, initial<em>suspend and final</em>suspend look like this:</p>

<pre><code class="language-c++">Future your_coroutine() {
    co_await promise.initial_suspend();
    // coroutine body here...
    co_await promise.final_suspend();
}
</code></pre>

<p>You could theoretically return anything you want here, but you&#39;ll likely be sticking with <code>ns::suspend_never</code>, which is an awaitable value that resumes execution of the coroutine immediately when <code>co_await</code>ed, and what we&#39;ll be using for this blog post.</p>

<p>Add the implementation to your promise type:</p>

<pre><code class="language-c++">ns::suspend_never initial_suspend() const noexcept { return {}; }
ns::suspend_never final_suspend() const noexcept { return {}; }
</code></pre>

<p>Your promise is responsible for taking care of any values that are <code>co_return</code>ed with the <code>return_value</code> function.</p>

<p>I recommend having two overloads: <code>const T&amp;</code> (copy value) and <code>T&amp;&amp;</code> (move value).</p>

<p>For our promise_type, the implementation of those will simply look like this:</p>

<pre><code class="language-c++">void return_value(const QVariant&amp; value) noexcept
{
    _future.succeed(value);
}
void return_value(QVariant &amp;&amp;value) noexcept
{
    _future.succeed(std::move(value));
}
</code></pre>

<p>If your coroutine was returning something like a <code>std::unique_ptr&lt;T&gt;</code>, you would need the <code>std::move</code> in order to properly handle it, and thus why I say you should have this overload in your promise type.</p>

<p>With get<em>return</em>object, initial<em>suspend, final</em>suspend, and return_value, you only have one remaining function left to implement in your coroutine. It&#39;s quite simple.</p>

<pre><code class="language-c++">void unhandled_exception() noexcept {

}
</code></pre>

<p>This is what gets called in the catch block of a try/catch block catching exceptions that the coroutine might throw. Use <code>std::current_exception()</code> to access the exception.</p>

<p>For this blog post, we&#39;ll simply be doing <code>Q_ASSERT(&#34;unhandled exception&#34;);</code> in our implementation.</p>

<p>With that, the promise type is complete. It should look something like this:</p>

<pre><code class="language-c++">struct promise_type {
    Future _future;

    Future get_return_object() noexcept {
        return _future;
    }

    ns::suspend_never initial_suspend() const noexcept { return {}; }
    ns::suspend_never final_suspend() const noexcept { return {}; }

    void return_value(const QVariant&amp; value) noexcept
    {
        _future.succeed(value);
    }
    void return_value(QVariant &amp;&amp;value) noexcept
    {
        _future.succeed(std::move(value));
    }

    void unhandled_exception() noexcept {
        Q_ASSERT(&#34;unhandled exception&#34;);
    }
};
</code></pre>

<p>Remember that this needs to be within the Future type itself, or within the appropriate coroutine_traits overload.</p>

<h2 id="the-awaitable">The Awaitable</h2>

<p>With the Future and promise completed, we don&#39;t have much left to do. We now need to implement <code>operator co_await(Future)</code> in order to allow the <code>Future</code> to be awaited.</p>

<p>Technically, we don&#39;t need the promise type to make a Future awaitable, only the Future and the co_await overload. Implementing a promise type allows your coroutine that&#39;s <code>co_await</code>ing a Future to return another Future.</p>

<p>There&#39;s not really much to the co_await overload, so I&#39;ll just paste an implementation verbatim:</p>

<pre><code class="language-c++">auto operator co_await(Future it) noexcept
{
    struct Awaiter {
        Future future;

        bool await_ready() const noexcept {
            return future.settled();
        }
        void await_suspend(ns::coroutine_handle&lt;&gt; cont) const {
            future.then([cont](QVariant) mutable {
                cont();
            });
        }
        QVariant await_resume() {
            return future.result();
        }
    };

    return Awaiter{ it };
}
</code></pre>

<p>co_await needs to return a type with the following methods:</p>

<p><code>bool await_ready() const noexcept</code>: This function is called before suspending the coroutine to wait on the awaitable to resolve. If the function returns true, the coroutine continues execution without suspending. If the function returns false, it suspends and waits on the value.</p>

<p>Think back to the example of a function returning an already succeeded future to see why this is useful. If the future already holds a value, there&#39;s no need to waste time suspending the coroutine.</p>

<p><code>void await_suspend(ns::coroutine_handle&lt;&gt; callback) const</code>: This function is called when the coroutine suspends with a coroutine handle passed in. For all intents and purposes, you can treat it as if it were a <code>std::function</code> holding a callback, except <code>operator ()</code> resumes the coroutine instead of calling a function.</p>

<p>You call the coroutine_handle to resume the coroutine when whenever it&#39;s waiting on is ready, e.g. when the future in this example is marked as succeeded. You can connect this to just about anything, e.g. a QTimer::singleShot, a signal, using it as a callback, etc.</p>

<p><code>T await_resume() const</code>: This is the value that gets assigned to the result of co_awaiting the expression:</p>

<pre><code class="language-c++">auto it = co_await fetchFromNetwork();
  // |
  // ^ this is the value from await_resume()
</code></pre>

<p>Annd with all three types implemented, you now have a QML-friendly future, a promise, and an awaitable.</p>

<h2 id="a-brand-new-washing-machine">A Brand New Washing Machine</h2>

<p>With your new coroutine, you can do just about anything asynchronously. This is an example function that returns a future that will be fufilled in N miliseconds:</p>

<pre><code class="language-c++">Future timer(int duration) {
    Future it;

    QTimer::singleShot(duration, [it]() {
        it.succeed({});
    });

    return it;
}
</code></pre>

<p>Note that while it returns a Future, it is not a coroutine. It does not <code>co_await</code>. This is a completely normal function that you can call however you desire.</p>

<p>Making a coroutine using this function is easy:</p>

<pre><code class="language-c++">Future thisIsACoroutine() {
    co_await timer(2000);

    co_return {};
}
</code></pre>

<p>Note that this function could not return void. The return type of a coroutine has to have an associated promise type, which <code>void</code> does not.</p>

<p>In a class exposed to QML...</p>

<pre><code class="language-c++">class Singleton : public QObject
{
    Q_OBJECT

public:
    Q_INVOKABLE Future foo() {
        co_await timer(2000);

        co_return &#34;i was returned by a coroutine&#34;;
    };
};
</code></pre>

<p>This can be used like so:</p>

<pre><code class="language-c++">Button {
    anchors.centerIn: parent
    text: &#34;a coroutine!&#34;
    onClicked: Singleton.foo().then((val) =&gt; {
        console.warn(val)
    })
}
</code></pre>

<p>This will output the following in your console 2 seconds after every time you press this button:</p>

<pre><code class="language-c++">qml: &#34;i was returned by a coroutine&#34;
</code></pre>

<p>The inline code from this blog post can be found in a single-file format at <a href="https://invent.kde.org/-/snippets/1711" rel="nofollow">https://invent.kde.org/-/snippets/1711</a>. Compile with C++20 and <code>-fcoroutines-ts -stdlib=libc++</code> for clang, and <code>-fcoroutines</code> for gcc.</p>

<p>For a basic future+promise+awaitable deal, this is about all you need to know. However, the iceberg gets way deeper than that.</p>

<p>Stay tuned for more blog posts about the eldritch arcana you can pull off with coroutines. Next one will probably be about wrapping already-existing types such as a <code>QNetworkReply*</code> in order to make them <code>co_await</code>-able.</p>

<p>You can see more advanced (and arguably useful) code at <a href="https://invent.kde.org/cblack/coroutines" rel="nofollow">https://invent.kde.org/cblack/coroutines</a>.</p>

<h2 id="contact-me">Contact Me</h2>

<p>Note that I wrote this blog post at 2 in the morning. If there&#39;s anything that doesn&#39;t make sense, please feel free to come to me and ask for clarification.</p>

<p>Or, want to talk to me about other coroutine stuff I haven&#39;t discussed in this blog post (or anything else you might want to talk about)?</p>

<p>Contact me here:</p>

<p>Telegram: <a href="https://t.me/pontaoski" rel="nofollow">https://t.me/pontaoski</a>
Matrix: <a href="https://blog.blackquill.cc/tag:pontaoski" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">pontaoski</span></a>:tchncs.de (prefer unencrypted DMs)</p>

<p>Tags: <a href="https://blog.blackquill.cc/tag:libre" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">libre</span></a></p>
]]></content:encoded>
      <guid>https://blog.blackquill.cc/c-coroutines-or-why-are-the-templates-failing-aaaaaaaaaaaa</guid>
      <pubDate>Tue, 15 Jun 2021 06:41:40 +0000</pubDate>
    </item>
  </channel>
</rss>