Thread overview
Result handing in D: some|none
Jan 30, 2022
9il
Jan 30, 2022
9il
Jan 30, 2022
SealabJaster
Jan 30, 2022
SealabJaster
January 30, 2022

mir.algebraic additions:

  • some, none, and suit second level algebraic visitor handlers
  • @reflectErr UDA
  • Err auto expanded wrapper when @reflectErr can't be used
  • Required utility API
import mir.algebraic;
import mir.conv: to;

alias orElse(alias fun) = visit!(some!"a", none!fun);
alias convertErrToString = orElse!(to!string);

// can be any other type including integer enums
@reflectErr
static struct ErrorInfo {
    string msg;
    auto toString() const { return msg; }
}

alias V = Variant!(Err!string, ErrorInfo, long, double);
alias R = typeof(convertErrToString(V.init));

static assert(is(R == Variant!(string, long, double)), R.stringof);
assert(convertErrToString(V(1)) == 1);
assert(convertErrToString(V(1.0)) == 1.0);
assert(convertErrToString(ErrorInfo("b")) == "b");
assert(convertErrToString("Ш".err) == "Ш");
January 30, 2022

On Sunday, 30 January 2022 at 10:58:33 UTC, 9il wrote:

>

mir.algebraic

I like suit a lot. It helps to define very clean visitors.

import std.traits: isDynamicArray, Unqual;
import std.meta: templateNot;
alias V = Variant!(long, int, string, long[], int[]);
alias autoGetElementType = match!(
    (string s) => "string", // we override the suit handler below for string
    suit!(isDynamicArray, a => Unqual!(typeof(a[0])).stringof),
    suit!(templateNot!isDynamicArray, a => Unqual!(typeof(a)).stringof),
);
assert(autoGetElementType(V(string.init)) == "string");
assert(autoGetElementType(V((long[]).init)) == "long");
assert(autoGetElementType(V((int[]).init)) == "int");
assert(autoGetElementType(V(long.init)) == "long");
assert(autoGetElementType(V(int.init)) == "int");
January 30, 2022

On Sunday, 30 January 2022 at 10:58:33 UTC, 9il wrote:

>

...

Nice work!

Anytime I see things like this it makes me wish D would adopt some form of pattern matching.

I've been using F# a lot lately, and I'm in love with how expressive it can be in certain cases, i.e.:

let (|Seconds|NotANumber|) (str : string) =
    let mutable value = 0.0
    match Double.TryParse(str, &value) with
    | true -> Seconds value
    | false -> NotANumber

...somewhere in an expression/function

       match model.Duration with
       | Seconds s -> ValidRequest {
                ...omitted
            }
       | NotANumber -> InvalidRequest "Duration is not a valid number"
January 30, 2022

On Sunday, 30 January 2022 at 16:08:17 UTC, SealabJaster wrote:

>

On Sunday, 30 January 2022 at 10:58:33 UTC, 9il wrote:

>

...
...
I missed the full example I wanted to give:

let (|Seconds|NotANumber|) (str : string) =
    let mutable value = 0.0
    match Double.TryParse(str, &value) with
    | true -> Seconds value
    | false -> NotANumber

let (|ValidRequest|InvalidRequest|) (model : PutSubModel, rs : ResultSet) =
    if model.Taken > DateTimeOffset.UtcNow then
        InvalidRequest "This result was taken in the future?"
    ...
    else
        match model.Duration with
        | Seconds s -> ValidRequest {
               ...
            }
        | NotANumber -> InvalidRequest "Duration is not a valid number"

let rec handleModel (model: PutSubModel) (array: PutSubModel[]) =
    match (model, rs) with
    | InvalidRequest error -> Some error
    | ValidRequest req ->
        req |> db.Add |> ignore
        if array.Length = 0 then
            None
        else
            handleModel array.[0] array.[1..]