Thread overview
Implicit conversion from 'Ok' to 'Result' type when returning functions
May 21, 2017
David Zhang
May 21, 2017
Nicholas Wilson
May 21, 2017
David Zhang
May 21, 2017
Nicholas Wilson
May 21, 2017
David Zhang
May 21, 2017
Nicholas Wilson
May 23, 2017
David Zhang
May 21, 2017
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
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
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
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
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
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 23, 2017
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)"