On 26/05/2017 02:30, Niall Douglas wrote:
This is precisely why I added a formal empty state, and default initialised to that. Because it causes behaviour different to valued or errored, it **very** effectively traps logic errors during code development. On **many** occasions it has successfully illuminated poorly thought through code that I have written by bringing to my attention - early and very obviously - that someone was very wrong. I am absolutely convinced it is a great design choice.
My worry with the formal empty state is precisely that as neither a value nor an error, someone might fail to check for it in code and then proceed under a false assumption. (If not has_error() then this void method must have succeeded, and I don't call value() because it was void.) Provided that .value() and .error() both throw if called in the empty state (which I assume is the case), that helps mitigate a large part of that, but not entirely, as in the case above. Yes, it's a misuse of the type, but it's one that I can see being very likely to happen in the real world. Even if the possibility of an empty state is heralded with bold blinking all-caps on all doc pages.
I'd therefore be happier with default construction giving uninitialised contents, or a default constructed T or E. No overloading state of E.
I strongly agree with Peter Dimov that introducing uninitialized state is a very undesirable thing. I still regard it as very rare in the majority of codebases that sanitizers that would detect that sort of thing would ever be run, so this would simply introduce the very type of UB that having a formal error-handling type is intended to reduce. I don't like the idea of a default-constructed T because T is not always default-constructible, and this makes it inconsistently behaved for different T and makes it harder to use uniformly in containers, especially in generic code. I don't like the idea of a default-constructed E because by convention (even if not quite in fact as Niall has pointed out -- though I've yet to see a platform where a 0 error code *didn't* mean success, other than cases where the formal type is int but is actually used as bool) the default-constructed error_code means "no error", and this is heavily reinforced by its operator bool semantics. I do like the idea of a non-default-constructed error code, because failure to initialise the result does seem like an error to me. Niall points out that this is harder to detect and treat specially in code but I don't agree with that; as long as a suitably unique error code is used then a simple assert in the error path would pick it up, no problem. If the consensus is that an initial non-default error code is not satisfactory, then a formal empty state seems to me like the least worst alternative. I just know that it's going to bite someone at some point.