I've been playing around with std.variant.Algebraic, trying to define a very simple option type. However, I've been running into quite a few problems. My implementation is as follows:

import std.conv;
import std.variant;

struct Some(T)
{
    T payload;

    alias payload this;
}

struct None
{
}

struct Option(T)
{       
    Algebraic!(Some!T, None) payload;

    alias payload this;
}

Option!int unreliable(int val)
{
    if (val == 0)
    {
        return None();
    }
    else
    {
        return Some!int(val);
    }
}


Unfortunately, I can't return values of type Some or None from "unreliable" and expect the compiler to know that they should become an Algebraic wrapped in an Option. This is annoying, but I can't expect magic. Maybe if I'm explicit:

Option!int unreliable(int val)
{
    if (val == 0)
    {
        //Nope
        return cast(Option!int)None();
    }
    else
    {
        //Nope
        return cast(Option!int)Some!int(val);
    }
}

Option!int unreliable(int val)
{
    if (val == 0)
    {
        //Nope
        return cast(Option!int)None();
    }
    else
    {
        //Nope
        return cast(Option!int)Some!int(val);
    }
}

Option!int unreliable(int val)
{
    if (val == 0)
    {
        //Nope
        return cast(Algebraic!(Some!int, None))None();
    }
    else
    {
        //Nope
        return cast(Algebraic!(Some!int, None))Some!int(val);
    }
}


Okay, I'll try constructing a fresh struct and returning that:

Option!int unreliable(int val)
{
    if (val == 0)
    {
        //Nope
        return Option!int(None());
    }
    else
    {
        //Nope
        return Option!int(Some!int(val));
    }
}


One final, last-ditch effort:

Option!int unreliable(int val)
{
    if (val == 0)
    {
        return Option!int(cast(Algebraic!(Some!int, None))None());
    }
    else
    {
return Option!int(cast(Algebraic!(Some!int, None))Some!int(val));
    }
}


Yes! It worked. The only problem is that this is completely unacceptable to type. The only other solution I can think of would be to define constructors for Option that take a Some and a None. I suppose it's not *all* bad, though. I mean, it compiles...

void main()
{
    auto maybeNone = unreliable(10);
//Error: template std.variant.visit cannot deduce template function from argument types !()(Option!(int))
    assert(maybeNone.visit!((Some!int s) => text("Value is ", s),
                            (None n) => "No value")
                    == 10);
}


I don't know whether to laugh or cry.

Reply via email to