Idiomatic way to express errors without resorting to exceptions
Basile B.
b2.temp at gmx.com
Sat Feb 29 15:01:37 UTC 2020
On Saturday, 29 February 2020 at 12:50:59 UTC, Adnan wrote:
> I have a struct that has to arrays. Each of those must have the
> same sizes.
>
> So while constructing the array, if you pass two arrays of
> different sizes the constructor must return nothing.
>
> In Rust I could easily use Option<T>. D has no answer to
> Optional types as far as I am concerned. Is throwing exceptions
> the only idiomatic way?
>
>
> ---
>
> What I already considered:
>
> * Using Nullable!T: Okay but Nullable!T has all the overloads
> for regular T which makes the API even more unpredictable.
>
> In Rust you don't just add a Some(44) and 34; No overloads for
> Some<T> and i32 are allowed (purposefully).
>
> * Option!T from the optional package: Has even worse problem
> IMO. Not only it allows None + int but also it returns a `[]`.
> This API is not to my liking. You could say well Haskell has
> fmap for Optional etc, and I am aware of that, so does Rust
> with map etc. But I am talking about basic things: like `+`.
>
> * Value-based error handling like Go and C: well, that works
> but the error checking is opt-in. There's no such thing as
> [[nodiscard]] in D too so the user of the API might as well
> forget to check for error value.
>
> * if specialization: Clever workaround but sometimes the struct
> may fail for complex reasons, not only for a single condition.
There's no idiomatic way since D lang is based on exceptions...
However I'd use one of those system:
1. return error, write result in ref parameter.
alias CheckedValueProto(RT, P...) = bool function(ref RT, P
params);
2. the same using a special struct and no more ref param. So more
like Nullable/Optional but with a dedicated generic type that
contain a single opover used to indicate if there's been an error
or not.
struct CheckedValue(T) {
bool noError;
T t;
B opCast(B : bool)() inout pure nothrow @safe {
return noError;
}
}
and you make your functions to return CheckedValues...
CheckedValue!int strToInt(string input);
....
if (const CheckedValue!int = strToInt("a") {} else {}
Although
- both still require self-discpline or a specialized linter to
detect unchecked calls ;
- the whole standard library is incompatible ;
I have a personal preference for 2. even if it causes problems
when T is of same size as a pointer. Now the question is also
what's the more costly ? try/catch or this non atomic return ?
More information about the Digitalmars-d-learn
mailing list