<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Sun, 8 Jun 2025 at 11:22, Stewart Becker &lt;<a href="mailto:stewart@sibecker.co.uk">stewart@sibecker.co.uk</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><u></u>

  
    
  
  <div>
    <p><br>
    </p>
    <div>On 07/06/2025 22:09, Jonathan Wakely
      wrote:<br>
    </div>
    <blockquote type="cite">
      
      <div dir="auto">
        <div><br>
          <br>
          <div class="gmail_quote">
            <div dir="ltr" class="gmail_attr">On Sat, 7 Jun 2025, 20:26
              Stewart Becker, &lt;<a href="mailto:stewart@sibecker.co.uk" target="_blank">stewart@sibecker.co.uk</a>&gt;
              wrote:<br>
            </div>
            <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
              <div>
                <p>Thank you, Jonathan for your insights.  <br>
                </p>
                <div>On 07/06/2025 15:35, Jonathan Wakely wrote:<br>
                </div>
                <blockquote type="cite">
                  <div dir="ltr">
                    <div dir="ltr"><br>
                    </div>
                    <br>
                    <div class="gmail_quote">
                      <div dir="ltr" class="gmail_attr">On Sat, 7 Jun
                        2025 at 15:15, Jonathan Wakely &lt;<a href="mailto:cxx@kayari.org" rel="noreferrer" target="_blank">cxx@kayari.org</a>&gt;
                        wrote:<br>
                      </div>
                      <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
                        <div dir="auto">
                          <div><br>
                          </div>
                        </div>
                      </blockquote>
                      <div><br>
                      </div>
                      <div>N.B. calling future::get() doesn&#39;t
                        necessarily mean that calling it again is UB.
                        It&#39;s specified to change valid() to false, but
                        whether that&#39;s UB is up to the implementation,
                        and recommended practice is to diagnose it by
                        throwing, so no UB.</div>
                    </div>
                  </div>
                </blockquote>
                <p>According to <a href="https://en.cppreference.com/w/cpp/thread/future/get" rel="noreferrer" target="_blank">https://en.cppreference.com/w/cpp/thread/future/get</a>,
                  calling get() when valid() is false is UB.  The
                  standard doesn&#39;t say this explicitly, but it does say
                  that get() retrieves the value/throws the exception
                  stored in the shared state, which doesn&#39;t exist when
                  valid() is false.  Thus the behaviour of get() when
                  valid() is false is literally undefined.  But I
                  concede that it&#39;s not called out as UB either. 
                  Perhaps this needs addressing in a separate issue?<br>
                </p>
              </div>
            </blockquote>
          </div>
        </div>
        <div dir="auto"><br>
        </div>
        <div dir="auto">It says it here: </div>
        <div dir="auto"><br>
        </div>
        <div dir="auto"><a href="https://eel.is/c++draft/futures#unique.future-3" target="_blank">https://eel.is/c++draft/futures#unique.future-3</a></div>
        <div dir="auto"><br>
        </div>
        <div dir="auto">But it also recommends that it should be defined
          to throw by implementions. So they should check for the &quot;no
          state&quot; case and throw, not just crash or set fire to your
          toes.</div>
        <div dir="auto"><br>
        </div>
        <div dir="auto">And that&#39;s why I think that the right way to
          phrase the behaviour of your proposal is in terms of whether
          valid() is true or false. Because then paragraph 3 days what
          happens (and depending on the implementation, it might not be
          UB).</div>
      </div>
    </blockquote>
    Thank you for the pointer.  You&#39;ve already convinced me that
    defining the behaviour in terms of valid() is true is the way
    forward.<br>
    <blockquote type="cite">
      <div dir="auto">
        <div dir="auto">
          <div class="gmail_quote">
            <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
              <div>
                <p> </p>
                <p>Calling std::future&lt;T&gt;::get() sets valid() to
                  false, even for future&lt;void&gt;, because the future
                  releases the shared state as a side-effect of calling
                  get().   The &quot;result&quot; may not be changed, but the
                  future itself is.  We absolutely don&#39;t want
                  get_exception() to invalidate the future - at least
                  when there is a good result in the shared state, as we
                  need to be able to call get() later.  This is less
                  important when there is an exception rather than a
                  value in the shared state, but for get_exception() to
                  invalidate the future in some cases but not in others
                  would complicate matters to no obvious benefit.<br>
                </p>
              </div>
            </blockquote>
          </div>
        </div>
        <div dir="auto"><br>
        </div>
        <div dir="auto">Agreed. And exception_ptr is already reference
          counted so if you get a copy of the future&#39;s exception_ptr, it
          remains valid even if the future goes away. OK, you&#39;ve
          convinced me.</div>
      </div>
    </blockquote>
    <p>Thank you.<br>
    </p>
    <p><br>
    </p>
    <blockquote type="cite">
      <div dir="auto">
        <div dir="auto">I&#39;m probably just being unimaginative but I
          don&#39;t see why you&#39;d want to stay in the &quot;future space&quot; and
          return another future when you&#39;ve already extracted the result
          (or the exception) from it. Doesn&#39;t that just add more
          overhead to have to get the result (or exception) out of the
          future again?</div>
      </div>
    </blockquote>
    <blockquote type="cite">
      <div dir="auto">
        <div dir="auto">I suppose for the or_else case, the future you
          return for the exceptional case might not be ready yet, so
          allows more asynchronous work. </div>
        <div dir="auto"><br>
        </div>
        <div dir="auto">But for the when_any case, don&#39;t you end up
          waiting for a result, and so there&#39;s no more asynchronous
          work? It always returns a ready future, so could just return
          the result instead. I suppose staying in the &quot;future space&quot;
          allows you to combine the returned future into another
          when_any call, or some other monad working with futures.</div>
      </div>
    </blockquote>
    Exactly.  In a word, the reason for staying in future-space is
    composition.</div></blockquote><div><br></div><div>Ack.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>  Also bear in mind that futures aren&#39;t only used for
    asynchronous work, they can also be used for deferred, sychronous
    work.<br></div></blockquote><div><br></div><div>Sure, but again, your when_any would execute any deferred work to make (at least) one of the futures ready, right?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>
    <p>I don&#39;t see why it would be more overhead with get_exception(). 
      In fact, when T is an expensive-to-move type, then get_exception()
      allows us to test for success/failure without paying for that cost
      of moving T until we call get().</p></div></blockquote><div><br></div><div>I don&#39;t like the suggestion that get_exception() would be used for &quot;do we have a result?&quot; queries, because that seems backwards i.e. asking &quot;is it ready and did it fail?&quot; seems like a bad alternative to &quot;is it ready and did it succeed?&quot; ... I realise currently we have neither. We don&#39;t even have &quot;is it ready?&quot; you can only do wait_for(0s) == future_status::ready.</div><div><br></div><div>But if we had a cheap &quot;is a successful result ready?&quot; query I think that would be preferable to trying to retrieve the exception and using &quot;null exception_ptr&quot; to mean it succeeded and there&#39;s a result. That doesn&#39;t mean get_exception() wouldn&#39;t be useful, I just think it shows we&#39;re missing _other_ useful members which would mean you don&#39;t need to use get_exception() to work around the absence of those members.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><p>  If we only have get_result(),
      we&#39;d pay the move cost twice - once when returning the
      std::expected from get_result(), and once more when extracting
      from the std::expected.<br>
    </p>
    <p>Ultimately, get_result() can be implemented in terms of
      get_exception() but not vice-versa, so get_exception() is the more
      fundamental feature.</p></div></blockquote><div>Fair point.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><p>  I am a fan of std::expected, and I do think
      that get_result() would be a great addition in its own right once
      std::expected supports references.  However, get_result() can&#39;t be
      implemented yet, and it isn&#39;t a complete alternative for
      get_exception().<br>
    </p>
    <br>
  </div>

</blockquote></div></div>

