June 06, 2023

I am trying to use std.sumtype which seems to be just what I need for some functions that can return various types of errors with parameters or a success value with different parameters.

In this test I get a compilation error with ldc2:

import std.stdio;
import std.sumtype;

struct Error {string message;}
struct Success {int s;}

SumType!(
        Error,
        Success)
    foo(string[] args)
{
    if (args.length > 1)
    {
        return Success(cast(int)args.length);
    }
    else
    {
        return Error("not enough arguments");
    }
}

int main(string[] args)
{
    foo(args).match!(
            (Error e) {writeln("Error ", e.message);},
            (Success s) {writeln("Success: ", s.s);});
    return 0;
}

It seems that the compiler does not want to convert an Error or Success value to the SumType!(Error, Success) value automatically.

Ok, well if I create an alias for the type and assign to an instance of that it seems to work:

import std.stdio;
import std.sumtype;

struct Error {string message;}
struct Success {int s;}

alias FooReturnType = SumType!(
        Error,
        Success);

FooReturnType foo(string[] args)
{
    FooReturnType fr;
    if (args.length > 1)
    {
        return fr = Success(cast(int)args.length);
    }
    else
    {
        return fr = Error("not enough arguments");
    }
}

int main(string[] args)
{
    foo(args).match!(
            (Error e) {writeln("Error ", e.message);},
            (Success s) {writeln("Success: ", s.s);});
    return 0;
}

Or if I just do a simple cast it also seems to work:

import std.stdio;
import std.sumtype;
import std.traits;

struct Error {string message;}
struct Success {int s;}

SumType!(
        Error,
        Success)
    foo(string[] args)
{
    if (args.length > 1)
    {
        return cast(ReturnType!foo)Success(cast(int)args.length);
    }
    else
    {
        return cast(ReturnType!foo)Error("not enough arguments");
    }
}

int main(string[] args)
{
    foo(args).match!(
            (Error e) {writeln("Error ", e.message);},
            (Success s) {writeln("Success: ", s.s);});
    return 0;
}

But both of those seem a little ugly. Is there a better approach than one of these two workarounds? Or a way to make the compiler ok with converting an Error or Success to a SumType!(Error, Success)?

ldc2 version:

LDC - the LLVM D compiler (1.28.0):
  based on DMD v2.098.0 and LLVM 11.1.0
  built with LDC - the LLVM D compiler (1.28.0)
  Default target: x86_64-pc-linux-gnu
  Host CPU: skylake
  http://dlang.org - http://wiki.dlang.org/LDC