Topic: About possible generalization of N3722 - Resumable functions


Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Sun, 05 Jan 2014 22:55:23 +0100
Raw View
This is a multi-part message in MIME format.
--------------010004070307030207010506
Content-Type: text/plain; charset=ISO-8859-1; format=flowed

Hi,

We are working on a proposal (see [1] and [2]) for a expected<t> class (something like an immediate future<T>). This class shares a lot of interfaces with std::future.
An example of a function using expected could be a madd function that return an expected with the the store values if both arguments are valid.

expected<int> madd(expected<int> a, expected<int> b) {
     return a.then([=](int x) {
     return b.then([=](int y) {
            return x+y;
     });
     });
}


The expected<T>::then() function has a continuation function as parameter. The continuation takes the underlying type as parameter.
Note that this differs from N3721 proposal and at the end both proposals would need to take the same approach..
expected<T> provides a recover function that takes a continuation with a exception_ptr as parameter.
The advantage of splitting the valid and invalid behavior is that the user code doesn't needs to check the validity or use try-catch blocks.

I was wondering if it would be acceptable to use the*await*  operator for expected types, which makes the code much clean and easy to read.


expected<int> madd(expected<int> a, expected<int> b) {
 return*await*  a +*await*  b;
}


Note that I have not tagged the function as resumable, as expected are always ready, that is, expected<T>::get() never blocks.

This madd function can be made more generic for any type M that is a '*Monad*'

template <class M>
// requires Monad<M>();
M madd(M a, M b) {
     return a.then([=](int x) {
     return b.then([=](int y) {
            return x+y;
     });
     });
}


This generic madd function could be used with future<U> and expected<U> or any other 'Monad' as e.g. optional<U>.

The question is how this function must be written using resumable/await. I don't know if the proposal included resumable function templates, but if not I think it is worth considering it.
It seems that it should be


template <class T>
// requires Monad<T>();
T madd(T a, T b)*resumable*  {
 return*await*  a +*await*  b;
}

but it is not evident that the type T is std::future<U> or shared_future<U> before instantiating it, so maybe the N3722 restrictions should be relaxed.

I was wondering also if resumable functions couldn't be resumable conditionally (as noexcept).

template <class T>
// requires Monad<T>();
T madd(T a, T b)*resumable**(is_blocking<T>::value)*  {
 return*await*  a +*await*  b;
}

The trait is_blocking<future<T>> would be true_type, while is_blocking<expected<T>> would be false_type.

When the function is not resumable the translation of await expr is much simpler as there is no need to track the resume point.

E.g.

expected<int> madd(expected<int> a, expected<int> b) {
 return*await*  a +*await*  b;
}


could be equivalent to

expected<int> madd(expected<int> a, expected<int> b) {
  auto x = await a;
  auto y = await b;
  return x +*y*;
}

that could be translated to


expected<int> madd(expected<int> a, expected<int> b) {
  if (!a.valid()) return exceptional(a);
  auto x = a.value();
  if (!b.valid()) return exceptional(a);
  auto y = b.value();
  return x +*y*;
}

expected provides an explicit conversion to exceptional that requires that the expected is not valid().
expected<T> is implicitly convertible from this exceptional class.
value() is like get() but requires that the expected is valid().

Comments?

Best,
Vicente


[1] https://github.com/ptal/std-expected-proposal
[2] https://github.com/ptal/Boost.Expected


--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

--------------010004070307030207010506
Content-Type: text/html; charset=ISO-8859-1

<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <meta http-equiv="content-type" content="text/html;
      charset=ISO-8859-1">
    <pre>Hi,

We are working on a proposal (see [1] and [2]) for a expected&lt;t&gt; class (something like an immediate future&lt;T&gt;). This class shares a lot of interfaces with std::future.
An example of a function using expected could be a madd function that return an expected with the the store values if both arguments are valid.

expected&lt;int&gt; madd(expected&lt;int&gt; a, expected&lt;int&gt; b) {
&nbsp;&nbsp;&nbsp; return a.then([=](int x) {
&nbsp;&nbsp;&nbsp; return b.then([=](int y) {
&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;  return x+y;
&nbsp;&nbsp;&nbsp; });
    });
}


The expected&lt;T&gt;::then() function has a continuation function as parameter. The continuation takes the underlying type as parameter.
Note that this differs from N3721 proposal and at the end both proposals would need to take the same approach..
expected&lt;T&gt; provides a recover function that takes a continuation with a exception_ptr as parameter.
The advantage of splitting the valid and invalid behavior is that the user code doesn't needs to check the validity or use try-catch blocks.

I was wondering if it would be acceptable to use the <b>await</b> operator for expected types, which makes the code much clean and easy to read.


expected&lt;int&gt; madd(expected&lt;int&gt; a, expected&lt;int&gt; b) {
 return <b>await</b> a + <b>await</b> b;
}


Note that I have not tagged the function as resumable, as expected are always ready, that is, expected&lt;T&gt;::get() never blocks.

This madd function can be made more generic for any type M that is a '<b>Monad</b>'

template &lt;class M&gt;
// requires Monad&lt;M&gt;();
M madd(M a, M b) {
&nbsp;&nbsp;&nbsp; return a.then([=](int x) {
&nbsp;&nbsp;&nbsp; return b.then([=](int y) {
&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;  return x+y;
&nbsp;&nbsp;&nbsp; });
    });
}


This generic madd function could be used with future&lt;U&gt; and expected&lt;U&gt; or any other 'Monad' as e.g. optional&lt;U&gt;.

The question is how this function must be written using resumable/await. I don't know if the proposal included resumable function templates, but if not I think it is worth considering it.
It seems that it should be


template &lt;class T&gt;
// requires Monad&lt;T&gt;();
T madd(T a, T b) <b>resumable</b> {
 return <b>await</b> a + <b>await</b> b;
}

but it is not evident that the type T is std::future&lt;U&gt; or shared_future&lt;U&gt; before instantiating it, so maybe the N3722 restrictions should be relaxed.

I was wondering also if resumable functions couldn't be resumable conditionally (as noexcept).

template &lt;class T&gt;
// requires Monad&lt;T&gt;();
T madd(T a, T b) <b>resumable</b><b>(is_blocking&lt;T&gt;::value)</b> {
 return <b>await</b> a + <b>await</b> b;
}

The trait is_blocking&lt;future&lt;T&gt;&gt; would be true_type, while is_blocking&lt;expected&lt;T&gt;&gt; would be false_type.

When the function is not resumable the translation of await expr is much simpler as there is no need to track the resume point.

E.g.

expected&lt;int&gt; madd(expected&lt;int&gt; a, expected&lt;int&gt; b) {
 return <b>await</b> a + <b>await</b> b;
}


could be equivalent to

expected&lt;int&gt; madd(expected&lt;int&gt; a, expected&lt;int&gt; b) {
 auto x = await a;
 auto y = await b;
&nbsp;return x + <b>y</b>;
}

that could be translated to


expected&lt;int&gt; madd(expected&lt;int&gt; a, expected&lt;int&gt; b) {
 if (!a.valid()) return exceptional(a);
 auto x = a.value();
 if (!b.valid()) return exceptional(a);
 auto y = b.value();
&nbsp;return x + <b>y</b>;
}

expected provides an explicit conversion to exceptional that requires that the expected is not valid().
expected&lt;T&gt; is implicitly convertible from this exceptional class.
value() is like get() but requires that the expected is valid().

Comments?

Best,
Vicente


[1] <a class="moz-txt-link-freetext" href="https://github.com/ptal/std-expected-proposal">https://github.com/ptal/std-expected-proposal</a>
[2] <a class="moz-txt-link-freetext" href="https://github.com/ptal/Boost.Expected">https://github.com/ptal/Boost.Expected</a>


</pre>
  </body>
</html>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href="http://groups.google.com/a/isocpp.org/group/std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/</a>.<br />

--------------010004070307030207010506--

.