expectations 0.1.0

Nick Sabalausky (Abscissa) SeeWebsiteToContactMe at semitwist.com
Mon Sep 3 21:55:57 UTC 2018


On 09/03/2018 02:49 AM, Paul Backus wrote:
> On Monday, 3 September 2018 at 04:49:40 UTC, Nick Sabalausky (Abscissa) 
> wrote:
>> Note that the above has *nothing* to do with retrieving a value. 
>> Retrieving a value is merely used by the implementation as a trigger 
>> to lazily decide whether the caller wants `foo` or `tryFoo`. Going out 
>> of scope without making the choice could also be considered another 
>> trigger point. In fact, this "out-of-scope without being checked" 
>> could even be used as an additional trigger for even the non-void 
>> variety. After all: what if an error occurs, but the caller checks 
>> *neither* value nor hasValue?
> 
> The thing is, triggering on explicit access lets you handle errors 
> lazily, whereas triggering at the end of the scope forces you to handle 
> them eagerly.
> 
> Vladimir's `Success` type is, essentially, a way for a function to send 
> something back up the stack that its caller is forced to acknowledge.

Yes, that's correct.

> Throwing an exception is *also* a way for a function to send something 
> back up the stack that its caller is forced to acknowledge.

Yes, but it's heavier-weight AND prevents the callee from being nothrow.

> but when it comes to overall control-flow 
> semantics, they are basically equivalent.

Control-flow semantics, sure, but as I pointed out in my previous 
sentence, there's more relevant things involved here than just control 
flow semantics.

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

To clarify: If the caller never checks value or hasValue, that does NOT 
mean the caller has carefully and deliberately chosen to disregard the 
error. It *could* mean that, but it could also mean they simply messed 
up. Deliberately squeching an error should NEVER be implicit, it should 
always require something like:

catch(...) { /+ Do nothing +/ }

or

if(!x.hasValue) { /+ Do nothing +/ }

> That's what being lazy 
> means: if you never open the box, it doesn't matter whether the cat is 
> alive or dead.

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.

> 
> Having one specialization be lazy and one be eager 
> would be a nightmare for anyone trying to use the library.

Vladimir's Success vs Expect!T is NOT an example of "eager vs lazy". In 
BOTH cases, the callee treats errors lazily. And in BOTH cases, the 
caller (or whomever the caller passes it off to) is expected to, at some 
point, make a deliberate, explicit choice between "handle or throw". And 
as I said before, allowing the caller to accidentally (or implicitly) 
squelch the error is a fundamental breakage in the whole point behind 
Except.


More information about the Digitalmars-d-announce mailing list