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
Correct for the example code I gave above.
But if you used `result<optional<filesystem::path>>` it would be suboptimal: you have one discriminator for `result` and one for `optional`.
I don't like typing .value().value(), correct.
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.
It's not a hack. The object provides a formal empty state for the programmer to do with as they wish. So I made use of that feature as it was intended for the programmer to use. Empty state still has the strongest, most abnormal default actions, but if you don't write code to trigger those default actions, then it's just a third state carrying no payload.
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.
The difference between the former and the latter is that internal to the implementation you're always going to have an empty state, at least under my implementation. So it's a case of choosing to expose it publicly (result<T>) or not (expected<T>) for programmers to use it directly, or not. In other words, it costs the implementation absolutely nothing to expose the empty state to the public API. So we can provide optional-type semantics at zero added cost. We could not do that for variant extensions like you described. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/