digitalmars.D.learn - Result Types and void usage
Hi all, I've been using D for a week now to compare it to Rust as a replacement to C++. One thing I miss from Rust is https://doc.rust-lang.org/std/result/ and its companion https://doc.rust-lang.org/std/macro.try!.html They make for some nice syntax so I had a go at recreating them in D (below): One thing I cant figure out/don't know if is possible is to have a type that takes "void" (see last unittest) For example in Rust a can declare a Result of Result<(), ErrorType> however I'm struggling to find the same semantics in D. Of course I can just use a bool but I'd prefer not to. Thank you for your time Nik Result type: struct Result(T, E) { this(inout T result) inout { _result = result; _is_result = true; } this(inout E error) inout { _error = error; _is_result = false; } bool is_result() const pure nothrow safe property { return _is_result; } T result() const pure nothrow safe property { return _result; } bool is_error() const pure nothrow safe property { return !_is_result; } E error() const pure nothrow safe property { return _error; } private: T _result; bool _is_result; E _error; } unittest { auto result = Result!(int, string)(1); assert(result.is_result); assert(result.result == 1); } unittest { auto result = Result!(int, string)("error"); assert(result.is_error); assert(result.error == "error"); } unittest { auto result_1 = Result!(int, string)(1); auto result_2 = Result!(int, string)(1); assert(result_1 == result_2); } unittest { auto result_1 = Result!(int, string)(1); auto result_2 = Result!(int, string)(2); assert(result_1 != result_2); } unittest { auto result_1 = Result!(int, string)(1); auto result_2 = Result!(int, string)("error"); assert(result_1 != result_2); } unittest { auto result_1 = Result!(int, string)("error"); auto result_2 = Result!(int, string)("error"); assert(result_1 == result_2); } unittest { auto result_1 = Result!(int, string)("an error"); auto result_2 = Result!(int, string)("error"); assert(result_1 != result_2); } unittest { enum ErrorType{A_Error, B_Error} auto result = Result!(int, ErrorType)(ErrorType.A_Error); assert(result.error() == ErrorType.A_Error); auto result_2 = Result!(immutable(bool), ErrorType)(true); assert(result_2.result()); Result!(immutable(bool), ErrorType) a_method() { return Result!(immutable(bool), ErrorType)(true); } assert(a_method().result()); } unittest { auto result_1 = Result!(bool, string)(true); assert(result_1.result); } //unittest //{ // auto result_1 = Result!(void, string)(void); // auto result_2 = Result!(void, string)(void); // assert(result_1.is_result); // assert(result_1 == result_2); //}
Jul 15 2016
On Friday, 15 July 2016 at 08:11:13 UTC, nik wrote://unittest //{ // auto result_1 = Result!(void, string)(void); // auto result_2 = Result!(void, string)(void); // assert(result_1.is_result); // assert(result_1 == result_2); //}You wanted to handle the void case? Because there are no void type you have to check the type at compile time. Enter static if... static if(!is(T == void)) { T result() const pure nothrow safe property { return _result; } } static if(!is(T == void)) T _result; static if(!is(T == void)) { this(inout T result) inout { _result = result; _is_result = true; } } else { this() { _is_result = true; //Or whatever semantics Rust use for void result } } And about conditional compilation (static if, version etc...): https://dlang.org/spec/version.html
Jul 15 2016
On 07/15/2016 10:11 AM, nik wrote:One thing I cant figure out/don't know if is possible is to have a type that takes "void" (see last unittest)[...]Result type: struct Result(T, E) { this(inout T result) inout { _result = result; _is_result = true; } this(inout E error) inout { _error = error; _is_result = false; } bool is_result() const pure nothrow safe property { return _is_result; } T result() const pure nothrow safe property { return _result; } bool is_error() const pure nothrow safe property { return !_is_result; } E error() const pure nothrow safe property { return _error; } private: T _result; bool _is_result; E _error; }void is somewhat special. It can't be used to declare variables or as a parameter type. So you'll have to approach this a bit differently. You also can't have a struct constructor with zero parameters. You can detect void and make it a special case where slightly different code is generated: ---- struct Result(T, E) { static if (!is(T == void)) this(inout T result) inout { ... } ... T result() const pure nothrow safe property { static if (!is(T == void)) return _result; } ... static if (!is(T == void)) T _result; bool _is_result = true; /* important when T is void */ } ---- [...]//unittest //{ // auto result_1 = Result!(void, string)(void); // auto result_2 = Result!(void, string)(void);`void` can't be an argument in D. Just leave the list empty: `Result!(void, string)()`.// assert(result_1.is_result); // assert(result_1 == result_2); //}
Jul 15 2016
On Friday, 15 July 2016 at 11:36:27 UTC, ag0aep6g wrote:On 07/15/2016 10:11 AM, nik wrote:Cool, that's neat and has the syntax I'm looking for. Thanks for your help Nik[...][...][...]void is somewhat special. It can't be used to declare variables or as a parameter type. So you'll have to approach this a bit differently. You also can't have a struct constructor with zero parameters. [...]
Jul 15 2016