On Tue, Jun 13, 2017 at 12:25 AM, Andrzej Krzemienski via Boost < boost@lists.boost.org> wrote:
let's not forget that if f() fails, y is invalid and g() should reject it (think of it as e.g. fread getting a 0 for its FILE * parameter).
I absolutely agree that it is wrong to pass an invalid `y` to `g()`, I think we are just disagreeing on who is responsible for preventing this from happening.
I think that I don't disagree at all, but I am pointing out that 1) no
matter what, g() *should* assert on its preconditions anyway, and 2) if
there is a danger for g() to silently not fail when given bad data, then
the choice of return type for f() is poor. For example, usually I'm not
terribly worried of the following bug escaping undetected:
shared_ptr<foo> f();
void g( foo & );
....
g(*f()); //bug, no error check
That's because dereferencing an empty shared_ptr fails dramatically, in
fact (if exceptions are disabled) just as dramatically as if I had:
result
where you could put this assertion, so that a call to `g()` is prevented. Maybe you could elaborate?
Misunderstanding. The call to g() is not prevented, what's prevented is the attempt of g() to call throw_ if the error from f() wasn't handled. But again, I agree with all of your concerns, it's just that they're (mostly, not 100%) orthogonal to what Noexcept lets you do. If you feel that you want to put a FILE * into some result<T>, more power to you (do note that since in Noexcept that type doesn't have to transport errors, it can be implemented in 2 lines in terms of optional<T>).
Perhaps your point is that ideally f() shouldn't return int but a different type with special semantics. Okay.
OTOH let's say you're returning a file descriptor. I'd think that optional<int> is an overkill in this case, in fact you're probably obfuscating the fact that the int is a FD -- what does it mean if you get -1 FD in an optional<int> (or for that matter in an outcome<int>)? It's redundant, and after all it's a safe assumption that you won't get silent failures from functions if you pass -1 for the FD.
A valid concern. A solution to that has been provided by Vicente: just use type `uncertain<T>`, which is just a `T` inside, but because it is a different type, you cannot silently use it in place of `T`. But this would compromise your other goal: that some functions want to remain exception-neutral.
How does it compromise it? This uncertain<T> must still have an invalid state, a value that is returned when there is an error. If that value is simply uncertain<T>() (which, obviously, it is), you can just return throw_(my_error()) from a neutral function that returns uncertain<T>.