Boost logo

Boost :

Subject: Re: [boost] [outcome] outcome without empty state?
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2017-05-27 23:38:01


2017-05-27 16:14 GMT+02:00 Niall Douglas via Boost <boost_at_[hidden]>:

> >>> This holds in principle but I'm not sure that result<T> should convert
> >>> into the hypothetical result_e<T>. From the discussion so far, I got
> the
> >>> impression that we don't want to return empty results from functions;
> it
> >>> seems to follow that result_e<T> would not be a return type, but the
> >>> type of the local variable in the function that is initially empty but
> >>> eventually acquires either a value or an error before being returned as
> >>> result<T>.
> >>
> >> That certainly is one design choice. I definitely have functions in
> >> KernelTest and AFIO which would be returning a result_e<T> as the empty
> >> return is part of the function's public contract. I gave an example of
> >> such a function a few days ago.
> >>
> >
> > Sorry, but the amount of threads to follow is getting difficult. Could
> you
> > point again to the example?
>
> http://boost.2283326.n4.nabble.com/review-Review-of-
> Outcome-starts-Fri-19-May-tp4694317p4694417.html
>
> Ok, let me quote it here again:

```
> // If this is empty, workspaces are identical
> result<stl1z::filesystem::path> workspaces_not_identical =
> compare_directories<false, false>(current_test_kernel.working_directory,
> model_workspace);
>
> // Propagate any error
> if(workspaces_not_identical.has_error())
> testret =
> error_code_extended(make_error_code(kerneltest_errc::filesystem_comparison_internal_failure),
>
> workspaces_not_identical.get_error().message().c_str(),
>
> workspaces_not_identical.get_error().value());
>
> // Set error with extended message of the path which differs
> else if(workspaces_not_identical.has_value())
> testret =
> error_code_extended(make_error_code(kerneltest_errc::filesystem_comparison_failed),
>
> workspaces_not_identical.get().string().c_str());
> ```
>
> So compare_directories() walks two directory structures using the
> Filesystem TS and compares them for equivalence using fuzzy criteria.
> Here we use the empty state to indicate "directory trees are identical",
> an error state to indicate an error occurred, and a valued state to give
> the path of the first item which differed.
>

So, what I am seeing here (correct me if I am wrong), is that conceptually
(performance considerations excluded) a return type that clearly reflects
your intentions would be:

```
result<optional<filesystem::path>>
```

That is:
 * either a path representing the first difference, or
 * no path (but no error) meaning that there was no difference, or
 * information or error that prefvented you from giving the answer

But if you used `result<optional<filesystem::path>>` it would be
suboptimal: you have one discriminator for `result` and one for `optional`.
So you applied a "hack": since, result's discriminator can handle one
additional state fo free, allow it to also represent optional objects. This
departs from the philosophy you described earlier, that "empty" state is
the most abnormal of all states.

But all-in-all the code is faster (I think), but what if in some other
project you find it convenient to return "either a filesystem::path or
file_desriptor":

```
result<variant<filesystem::path, file_descriptor>>
```

And again, this is suboptimal, as the result's discriminator could also
handle two states of the variant's discriminator. Are you going to provide
yet another "shades" for `result`:

```
result_variant<filesystem::path, file_descriptor>
```

This is also a useful optimization, but should library handle all possible
optimizations for particular problems is user's code? I believe users
should apply such improvements themselves, not via a generic tool.

Regards,
&rzej;


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