expectations 0.1.0

Paul Backus snarwin at gmail.com
Tue Sep 4 04:05:16 UTC 2018


On Monday, 3 September 2018 at 21:55:57 UTC, Nick Sabalausky 
(Abscissa) wrote:
>> By contrast, a function that returns an `Expected!T` does 
>> *not* force its caller to acknowledge it. If an error occurs, 
>> and the caller never checks value or hasValue...nothing 
>> happens.
>
> That's called squelching an error, and its EXACTLY the same 
> problem as using non-Expect return values to indicate errors. 
> I'd regard that as very notable hole in any Expected design as 
> it breaks one of the core points of using Expect vs returning 
> plain error codes: The user can still accidentally (or 
> deliberately) squelch an error.

If you receive an `Expected!T`, you have the following choices 
available to you:

1. Handle the success case locally, and the failure case 
non-locally (i.e. use `value` directly).
2. Handle both the success case and the failure case locally 
(i.e. check `hasValue`).
3. Handle both the success case and the failure case non-locally 
(i.e., pass the `Expected!T` along untouched).

The difference between `Expected`, on the one hand, and both 
`Success` and plain-old exceptions, on the other, is that 
`Expected` gives you choice #3, and the other two don't.

Why is choice #3 important? Because it doesn't branch. Both 
success and failure follow the same code path. That makes 
functions that use `Expected` much easier to compose than ones 
that throw exceptions. For example, if you throw an exception in 
the middle of a range pipeline, the entire thing comes crashing 
down--but an `Expected!T` will pass right through, and let you 
handle it when it comes out the other end.

Now, you will probably object--and rightly so--that there is an 
implicit assumption being made here, which is that "handle the 
success case" is equivalent to "use the return value." Clearly, 
this equivalence does not always hold in the presence of side 
effects. That's why `Expected!void` is so problematic. 
Nevertheless, I think it holds in enough cases to make `Expected` 
useful in practice. In particular, it is guaranteed to hold for 
strongly-pure functions, and will also hold for functions whose 
side effects are visible only through the return value (e.g., 
`readln`).

> I don't see the laziness here as being the core point. The 
> laziness is the "how", not the raison d'etre. The laziness is 
> simply a tool being used to achieve the real goals of:
>
> - Allowing the caller the decide between foo/tryFoo versions 
> without the API duplication.
>
> - Decreasing exception-related overhead and increasing utility 
> of nothrow.

The laziness (on the part of the caller, i.e., the code that 
*receives* the `Expected!T`) is important because it's what makes 
choice #3 possible. It's an essential part of the design.


More information about the Digitalmars-d-announce mailing list