December 20, 2020
On Sunday, 15 November 2020 at 04:54:19 UTC, 9il wrote:
> Truly algebraic Variant and Nullable with an order-independent list of types.

Thanks for sharing it!

Could you give a (very short) explanation on why sumtype could not meet your requirements? I am just starting a new D project and have to choose between sumtype and your solution.

>
> The work has been sponsored by Kaleidic Associates and Symmetry Investments.

Much appreciated!


December 20, 2020
On Sunday, 15 November 2020 at 04:54:19 UTC, 9il wrote:
> Truly algebraic Variant and Nullable with an order-independent list of types.
>
> Nullable is defined as
> ```
> alias Nullable(T...) = Variant!(typeof(null), T);
> ```
>
> Variant and Nullable with zero types are allowed.
>
> `void` type is supported.
>
> Visitors are allowed to return different types.
>
> Cyclic referencing between different variant types are supported.
>
> More features and API:
>
> http://mir-core.libmir.org/mir_algebraic.html
>
> Cheers,
> Ilya
>
> The work has been sponsored by Kaleidic Associates and Symmetry Investments.

I have been using SumType [1] for a while in some of my projects and I'm quite happy with it. The author has been very responsive to feedback and the quality bar of his work is definitely higher than that of many other D libraries (e.g. support for @safe/pure/@nogc/nothrow, immutable, betterC and DIP1000, etc.).

That said, I'm also a fan of your work with Mir! mir.algorithm (which I'm most familiar with) is a text book example of high-quality generic algorithm design.

How does your work compare to sumtype? Would mir.algebraic offer any benefits, which would make it worth switching over?

IMO, algebraic types (sum and tuple types) should be a core language feature part of druntime and should have have corresponding syntax sugar:

// Same as Tuple!(T, "open", T, "high", T, "low", T, "close"):
alias OhlcTuple(T) = (T open, T high, T low, T close);

// Same as:
// Union!(long, double, bool, typeof(null), string,
//     This[], This[string];
alias Json =
    | long
    | double
    | bool
    | typeof(null)
    | string
    | Json[]
    | Json[string];

// Syntax sugar for nullable/optional types -
// T? == Nullable!T == Union!(typeof(null), T):
alias ResponseParser = OhlcTuple!double? delegate(Json json);

If we can work together to consolidate on a single API, I think it would be better for the language ecosystem.

[1]: https://code.dlang.org/packages/sumtype
December 20, 2020
On Sunday, 20 December 2020 at 12:32:35 UTC, Petar Kirov [ZombineDev] wrote:
> On Sunday, 15 November 2020 at 04:54:19 UTC, 9il wrote:
>> [...]
>
> I have been using SumType [1] for a while in some of my projects and I'm quite happy with it. The author has been very responsive to feedback and the quality bar of his work is definitely higher than that of many other D libraries (e.g. support for @safe/pure/@nogc/nothrow, immutable, betterC and DIP1000, etc.).
>
> [...]

I'm increasingly thinking these should be a language feature, it just seems right.
December 21, 2020
On Sunday, 20 December 2020 at 11:00:05 UTC, Tobias Pankrath wrote:
> On Sunday, 15 November 2020 at 04:54:19 UTC, 9il wrote:
>> Truly algebraic Variant and Nullable with an order-independent list of types.
>
> Thanks for sharing it!
>
> Could you give a (very short) explanation on why sumtype could not meet your requirements? I am just starting a new D project and have to choose between sumtype and your solution.
>
>>
>> The work has been sponsored by Kaleidic Associates and Symmetry Investments.
>
> Much appreciated!

For me choose between sumtype and mir.algebraic ends when I not found
any solution for working with type kind [1] in sumtype. Kind represents in
taggedalgebraic [2] too, but it can't work in compile time (important for
me in current project). Also I find tagged_union [3] library, but it haven't
any visit [4] or match functions.

[1] http://mir-core.libmir.org/mir_algebraic.html#.TaggedVariant
[2] https://code.dlang.org/packages/taggedalgebraic
[3] https://code.dlang.org/packages/tagged_union
[4] http://mir-core.libmir.org/mir_algebraic.html#visit
December 21, 2020
On Sunday, 20 December 2020 at 12:38:47 UTC, Max Haughton wrote:
> On Sunday, 20 December 2020 at 12:32:35 UTC, Petar Kirov [ZombineDev] wrote:
>> On Sunday, 15 November 2020 at 04:54:19 UTC, 9il wrote:
>>> [...]
>>
>> I have been using SumType [1] for a while in some of my projects and I'm quite happy with it. The author has been very responsive to feedback and the quality bar of his work is definitely higher than that of many other D libraries (e.g. support for @safe/pure/@nogc/nothrow, immutable, betterC and DIP1000, etc.).
>>
>> [...]
>
> I'm increasingly thinking these should be a language feature, it just seems right.

+1 because it would allow for implicit overload resolution
December 22, 2020
On Sunday, 20 December 2020 at 11:00:05 UTC, Tobias Pankrath wrote:
> On Sunday, 15 November 2020 at 04:54:19 UTC, 9il wrote:
>> Truly algebraic Variant and Nullable with an order-independent list of types.
>
> Thanks for sharing it!
>
> Could you give a (very short) explanation on why sumtype could not meet your requirements? I am just starting a new D project and have to choose between sumtype and your solution.
>

Lets users do comparisons between libraries. Both are very good.

Some mir.algebraic features:

1. (optionally) Nullable algebraic types. Also serves as buggy Phobos Nullable replacement.
2. (optionally) Tagged algebraic types
3. Type list order-independent declaration
4. Feature-rich visitor handlers. For example, they can form new Algebraic types if the visitors return different types.
5. `void` support. This is an important brick for reflections on the algebra of type sets.
6. Algebraic type subsets are supported by `get`, `trustedGet`, `_is`, and `this` primitives. You can operate with algebraic subset as with the type of the original typeset. [1]
7. Members (fields and methods) reflection. Is more restrictive than in vibe.d implementation. It adds member reflection to an algebraic type if all of the types contain members with the same name.

Mir implements Algebra of (type) sets with reflections (functions) on it.

[1] https://github.com/libmir/mir-core/issues/33
December 22, 2020
On Sunday, 20 December 2020 at 12:32:35 UTC, Petar Kirov [ZombineDev] wrote:
> How does your work compare to sumtype? Would mir.algebraic offer any benefits, which would make it worth switching over?

replied at
https://forum.dlang.org/post/zlphfxktclgdookqtdrc@forum.dlang.org

> If we can work together to consolidate on a single API, I think it would be better for the language ecosystem.

Agreed. On the other hand, my public association with a DIP would be a red flag and will increase the chance the DIP would be declined. Cooperation is better to make silently.

December 22, 2020
On 22.12.20 04:56, 9il wrote:
> 6. Algebraic type subsets are supported by `get`, `trustedGet`, `_is`, and `this` primitives. You can operate with algebraic subset as with the type of the original typeset. [1]

"trustedGet" - That name smells of a safety violation. And indeed (compile with `-release`):

----
import mir.algebraic;
import std.stdio;
void main() @safe
{
    immutable int* x = new int(42);
    Variant!(size_t, int*) v;
    v = cast(size_t) x;
    auto p = v.trustedGet!(int*); /* uh-oh */
    *p = 13; /* mutating immutable */
    writeln(*x); /* prints "13" */
}
----

The normal `get` also violates safety by giving out references into the union (compile with `-preview=dip1000`):

----
import mir.algebraic;
import std.stdio;
T* ref_to_ptr(T)(ref T r) @safe { return &r; }
void main() @safe
{
    immutable int* x = new int(42);
    Variant!(size_t, int*) v;
    int** p = ref_to_ptr(v.get!(int*)); /* uh-oh */
    v = cast(size_t) x;
    **p = 13; /* mutating immutable */
    writeln(*x); /* prints "13" */
}
----

But that might be an issue with DIP1000. `ref_to_ptr` is a hint that something isn't right in that area.
December 22, 2020
On Tuesday, 22 December 2020 at 03:56:13 UTC, 9il wrote:
> On Sunday, 20 December 2020 at 11:00:05 UTC, Tobias Pankrath wrote:
>> On Sunday, 15 November 2020 at 04:54:19 UTC, 9il wrote:
>>> Truly algebraic Variant and Nullable with an order-independent list of types.
>>
>> Thanks for sharing it!
>>
>> Could you give a (very short) explanation on why sumtype could not meet your requirements? I am just starting a new D project and have to choose between sumtype and your solution.
>>
>
> Lets users do comparisons between libraries. Both are very good.
>
> Some mir.algebraic features:
>
> [...]
>
> Mir implements Algebra of (type) sets with reflections (functions) on it.

It seems like in general, the philosophy of sumtype is to provide the minimal set of features necessary to cover all possible use-cases ("mechanism, not policy"), whereas the philosophy of mir.algebraic is to include a large number of convenience features out-of-the-box.

The upside of mir.algebraic's approach is that it is easier to get started with. The downside is that, if you later discover that the convenience features are not quite what you want, you will be stuck reimplementing them yourself anyway--and at that point, the built-in versions will only get in your way.

They also introduce a lot of incidental complexity to the library. Take a look at the documentation [1] and you'll see a giant table describing the subtle differences in behavior between 12 (!) distinct accessor functions. By comparison, sumtype has exactly one accessor function, "match" [2], whose full behavior is documented in about the same amount of space.

[1] http://mir-core.libmir.org/mir_algebraic.html
[2] https://pbackus.github.io/sumtype/sumtype.match.html
December 22, 2020
On Tuesday, 22 December 2020 at 14:27:02 UTC, ag0aep6g wrote:
> On 22.12.20 04:56, 9il wrote:
>> 6. Algebraic type subsets are supported by `get`, `trustedGet`, `_is`, and `this` primitives. You can operate with algebraic subset as with the type of the original typeset. [1]
>
> "trustedGet" - That name smells of a safety violation. And indeed (compile with `-release`):

> The normal `get` also violates safety by giving out references into the union (compile with `-preview=dip1000`):

> But that might be an issue with DIP1000. `ref_to_ptr` is a hint that something isn't right in that area.

The definitions are

```
auto ref get(E)() @property return inout
auto ref trustedGet(E)() @trusted @property return inout nothrow
```

Both market with `return`.

According to the spec [1, example 2]

"Struct non-static methods marked with the return attribute ensure the returned reference will not outlive the struct instance."

The docs maybe not clear enough. `trustedGet` asserts type is matched, while `get` throws an exception if the type doesn't match.

[1] https://dlang.org/spec/function.html#return-ref-parameters