expectations 0.1.0

Nick Sabalausky (Abscissa) SeeWebsiteToContactMe at semitwist.com
Tue Sep 4 22:08:48 UTC 2018


On 09/04/2018 12:05 AM, Paul Backus wrote:
> 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.
> 

I think you may be getting hung up on a certain particular detail of 
Vladimir's exact "draft" implementation of Success, whereas I'm focusing 
more on Success's more general point of "Once the object is no longer 
around, guarantee the error doesn't get implicitly squelched."

You're right that, *in the draft implementation as-is*, it can be 
awkward for the caller to then pass the Success along to some other code 
(another function call, or something higher up the stack). *Although*, 
still not impossible. So #3 still isn't eliminated, it's simply made 
awkward...

But reference counting would be enough to fix that. (Or a 
compiler-supported custom datatype that's automatically pass-by-moving, 
but that's of course not something D has).

And you haven't actually directly addressed the issue I've raised about 
failing to guarantee errors aren't implicitly squelched.

> 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.

Right. And as described above, I'm advocating an approach that preserves 
that (even for void) while *also* improving Expect so it can not 
*merely* improve things "in most cases", but would actually *guarantee* 
errors are not implicitly squelched in ALL cases where Expect!whatever 
is used.

>> 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.

Again, what I'm proposing still preserves that.


More information about the Digitalmars-d-announce mailing list