Boost logo

Boost :

Subject: Re: [boost] [gsoc-2013] Boost.Expected
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2013-04-28 11:20:10


Le 28/04/13 16:22, Pierre T. a écrit :
> On 04/27/2013 03:30 PM, Vicente J. Botet Escriba wrote:
>> Le 27/04/13 09:39, Pierre T. a écrit :
>>> On 04/26/2013 08:17 PM, Vicente J. Botet Escriba wrote:
>>>> Le 26/04/13 14:22, Pierre T. a écrit :
>>> I like this proposition but at first, it seems a bit "overkill". I
>>> would like to have more opinions about it. Through it seems to be
>>> less compatible with the "visitor" idea. The visitor resolves on
>>> types and most of the error code have a same type. So it would visit
>>> only one type.
>> Right. But this independent on whether you use a wrapper exception or
>> not, isn't it?
> Yes, it gives a good point to the traits.
>>>
>>>> * Default Constructor or constructor from nullexpect
>>>> What is the advantage of having a expected instance that doesn't have
>>>> neither a value nor an exception?
>>>> How would the user manages with this possibility?
>>>> Are you looking to make expect movable?
>>>>
>>> Basically, I noticed that classes without default constructor (or
>>> default state) are burdensome to use. Indeed, you cannot store an
>>> expected in a class as a member if not initialized in the
>>> constructor. Or doing something like:
>>>
>>> expected<int> e;
>>> if(…)
>>> else(…)
>>> return e;
>>>
>>> Through, I removed the default constructor because I found it
>>> unclear. I use a nullexcept because it was a good idea in
>>> Boost.Optional with nullopt.
>> Yes it was one. But the definition of optional is there to allow a
>> state that means value not present. expected<> is designed to have a
>> value or an exception.
>> Could you answer to the question
>> How would the user manages with this possibility?
> By testing == nullexcept (operator== not in the proposal, sorry),
> however you are right, expected must contains an exception or a value.
> On the other hand, it's nice to provide a default constructor, so an
> idea could be to add a method "unitialized_error()" in the trait class.
Why do you need a default constructor.
>>>
>>> Finally, I'm not sure to understand how it's related to the movable
>>> ability of Boost.Expected.
>> I let you try to define move move semantics for expected and you will
>> see why this is related.
After thinking more on this the moved object could present its
exception_ptr if it has one, so move semantics doesn't force to have an
uninitialized expected<>
>>>
>>>> * then/otherwise issues
>>>>
>>>>
>>>> But the design error is not on the otherwise function but on the then
>>>> function.
>>>>
>>>> Resuming, I'm not more for the 'then' function.
>>>>
>>>
>>> I'm totally agree with you. But I think that I misnamed the
>>> "otherwise" method. I think the "then" method is really useful, it's
>>> like an automaton. With e.then().then().then(), the treatment is
>>> stopped anytime when an error occurs in a then method.
>> How would this be stopped? throwing and exception?
> It's not stopped but the "then" method launch the function only if
> expected contains a value.
And what return if it not contains a value?
>>> Also, I think that the function taken by then should return void
>> And which value would you pass to the second then call?
> The same.
Sorry I don't follow. What The do you mean by the same?
>>> or an expected.
>>
>> Maybe. But if we don't know how it is stopped chaining them has no
>> sens. When the call to the function is asynchronous it is easy to
>> stop it but synchronously it implies an exception which is against
>> the goal of expected.
>>> In fact the otherwise method is the error visitor. A common usage
>>> would be to chain it in the end:
>>>
>>> e.then(...).then(...).then(...).visit_error(error_visitor);
>>>
>>> visit_error is called if any "then" return an error. I found it
>>> wonderfully useful.
>> This could be possible; It would need that then() returns an
>> expression template storing all the functions on the chain and only
>> the call to the visit_error would evaluate the chain.
>> I don't think it is worth proving this lazy evaluation.
> To complete what I've said, the visit_error() would launch the visitor
> only if the expected contains an error. No lazy evaluation is needed.
Ah I think I see now what was the initial intention. I suspect that you
mean that as the result of e.then(f) would transport the exception
stored on e if e is not valid, then the exception would be relayed until
there is a call to visit_error and no call to any function will be done.
Yes this is quite similar if we had exceptions and we had a try/catch block

f0().then(f1).then(f2).then(f3).visit_error(error_visitor);

try {
   f3(f2(f1(f0())));
} catch(...) {
   error_visitor();
}

It would be great if we could have the equivalent for
try {
   h(f(), g());
} catch(...) {
   error_visitor();
}

when_all(f(), g()).then(h).visit_error(error_visitor);

when_all could return a expected<tuple<T1, T2>> or something more
specific so that then would extract the members of the tuple to call h
with two parameters.

This start to look more and more like the proposal for futures
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3558.pdf)

> I'll try to send it before tomorrow. I will update it with the trait
> classes and the others comments you made. I just have a question about
> the proposal, should I use the Boost macro for noexcept,… or is it
> better (for a proposal) to write it with the standard tools ?
I use to document using c++11 without any reference to the emulations.

Best,
Vicente


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk