www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Implicit conversion from 'Ok' to 'Result' type when returning

reply David Zhang <straivers98 gmail.com> writes:
Hi,

I was reading a bit about this in Rust, and their enum type. I 
was wondering if this is replicate-able in D. What I've got right 
now is rather clunky, and involves using

      `typeof(return).ok` and `typeof(return).error)`.

While that's not too bad, it does involve a lot more typing, and 
thus more area for human error.

If you're not familiar with the Result and Option types, it 
allows you to do something like this:

---
Result!(string, ErrorEnum) someFunction(...)
{
     return Ok("Hello!");
}

Result!(string, ErrorEnum) someFunction2(...)
{
     return Error(ErrorEnum.dummyError);
}
---

I'm not entirely sure it's possible... but I figured I might give 
it a try.
May 21 2017
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Sunday, 21 May 2017 at 08:44:31 UTC, David  Zhang wrote:
 Hi,

 I was reading a bit about this in Rust, and their enum type. I 
 was wondering if this is replicate-able in D. What I've got 
 right now is rather clunky, and involves using

      `typeof(return).ok` and `typeof(return).error)`.

 While that's not too bad, it does involve a lot more typing, 
 and thus more area for human error.

 If you're not familiar with the Result and Option types, it 
 allows you to do something like this:

 ---
 Result!(string, ErrorEnum) someFunction(...)
 {
     return Ok("Hello!");
 }

 Result!(string, ErrorEnum) someFunction2(...)
 {
     return Error(ErrorEnum.dummyError);
 }
 ---

 I'm not entirely sure it's possible... but I figured I might 
 give it a try.
have free functions Result!(T, ErrorEnum) ok(T)(T t) { return Result(t); } Result!(T, ErrorEnum) error(T)(ErrorEnum e) { return Result(e); } then go if (!foo) return ok(42); else return error(Error.fooHappened);
May 21 2017
parent reply David Zhang <straivers98 gmail.com> writes:
On Sunday, 21 May 2017 at 09:15:56 UTC, Nicholas Wilson wrote:
 have free functions

  Result!(T, ErrorEnum) ok(T)(T t) { return Result(t); }
  Result!(T, ErrorEnum) error(T)(ErrorEnum e) { return 
 Result(e); }

 then go

 if (!foo)
     return ok(42);
 else
     return error(Error.fooHappened);
Ah, I think you misread. ErrorEnum is a template type, like `T`. There's no ErrorEnum enum specified.
May 21 2017
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Sunday, 21 May 2017 at 09:29:40 UTC, David  Zhang wrote:
 On Sunday, 21 May 2017 at 09:15:56 UTC, Nicholas Wilson wrote:
 have free functions

  Result!(T, ErrorEnum) ok(T)(T t) { return Result(t); }
  Result!(T, ErrorEnum) error(T)(ErrorEnum e) { return 
 Result(e); }

 then go

 if (!foo)
     return ok(42);
 else
     return error(Error.fooHappened);
Ah, I think you misread. ErrorEnum is a template type, like `T`. There's no ErrorEnum enum specified.
Well then it becomes Result!(T, E) ok(T,E) (T t) { return Result(t); } Result!(T, E) error(T,E)(E e) { return Result(e); } and then provided it can be inferred (e.g. from the function signature) it will still work.
May 21 2017
parent reply David Zhang <straivers98 gmail.com> writes:
On Sunday, 21 May 2017 at 09:37:46 UTC, Nicholas Wilson wrote:
 On Sunday, 21 May 2017 at 09:29:40 UTC, David  Zhang wrote:
 Well then it becomes
  Result!(T, E) ok(T,E)     (T t) { return Result(t); }
  Result!(T, E) error(T,E)(E e) { return Result(e); }

 and then provided it can be inferred (e.g. from the function 
 signature)
 it will still work.
But how would it be inferred? Like the `ok` function, `T` could be inferred, but E? I'm not sure I understand. If you have to specify the types every time, it kinda defeats the purpose. With the function signature as it is, you'd have to specify the type of the other type (e.g. you'd need to specify E for `ok()`).
May 21 2017
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Sunday, 21 May 2017 at 09:55:41 UTC, David  Zhang wrote:
 On Sunday, 21 May 2017 at 09:37:46 UTC, Nicholas Wilson wrote:
 On Sunday, 21 May 2017 at 09:29:40 UTC, David  Zhang wrote:
 Well then it becomes
  Result!(T, E) ok(T,E)     (T t) { return Result(t); }
  Result!(T, E) error(T,E)(E e) { return Result(e); }

 and then provided it can be inferred (e.g. from the function 
 signature)
 it will still work.
But how would it be inferred? Like the `ok` function, `T` could be inferred, but E? I'm not sure I understand. If you have to specify the types every time, it kinda defeats the purpose. With the function signature as it is, you'd have to specify the type of the other type (e.g. you'd need to specify E for `ok()`).
As in the function signature of the function you call `ok` or `error` in. Result!(int, SomeEnum) myfunc(bool foo) { if(!foo) return ok(42); else return error(SomeEnum.fooHappened); } should work.
May 21 2017
parent David Zhang <straivers98 gmail.com> writes:
On Sunday, 21 May 2017 at 10:03:58 UTC, Nicholas Wilson wrote:
 As in the function signature of the function you call `ok` or 
 `error` in.

 Result!(int, SomeEnum) myfunc(bool foo)
 {
     if(!foo)
         return ok(42);
     else
         return error(SomeEnum.fooHappened);
 }

 should work.
This is what I've got right now. --- [module 1] struct Result(OkType, ErrType) { this(OkType ok) pure nothrow { isOk = true; okPayload = ok; } this(ErrType error) pure nothrow { isOk = false; errorPayload = error; } bool isOk; union { OkType okPayload; ErrType errorPayload; } } auto ok(T, E)(T payload) { return Result!(T, E)(payload); } auto error(T, E)(T payload) { return Result!(T, E)(payload); } --- [module 2] Result!(string, int) fn(bool shouldErr) { if (!shouldErr) return ok("No problem"); return error(0); } --- But it can't infer the second parameter. "template result.ok cannot deduce function from argument types !()(string)"
May 22 2017