June 15, 2020
On Sunday, 14 June 2020 at 18:04:57 UTC, Paul Backus wrote:
> FYI, SumType works with nothrow and @nogc, and can solve all of your other problems with std.variant as well. :)
>
> Duplicate types are not supported out-of-the-box, but can very easily be accomplished using `std.typecons.Typedef`:
>
>     alias InPixels = Typedef!(int[2], int[2].init, "InPixels");
>     alias InMeters = Typedef!(float[2], float[2].init, "InMeters");
>     alias SourceSizes = Typedef!(float[2], float[2].init, "SourceSizes");
>     alias PictureSize = SumType!(InPixels, InMeters, SourceSizes);

Supporting all attributes definitely sounds good. OTOH your example isn't as DRY as with Taggedalgebraic:

```
alias PictureSize = TaggedUnion!PictureSize_;
union PictureSize_
{   int[2] inPixels;
    float[2] inMeters;
    float[2] inSourceSizes;
}
```

In essence, the problem is that I want an union with a customizable tag, not an afterwards defined "base class" for the types. I'd check Atila's library first for the latter. But I definitely could adapt `SumType` for my use with some extra wrapping.
June 15, 2020
On Sunday, 14 June 2020 at 18:04:57 UTC, Paul Backus wrote:
> On Sunday, 14 June 2020 at 17:31:32 UTC, Dukc wrote:
>> [...]
>
> FYI, SumType works with nothrow and @nogc, and can solve all of your other problems with std.variant as well. :)
>
> Duplicate types are not supported out-of-the-box, but can very easily be accomplished using `std.typecons.Typedef`:
>
>     alias InPixels = Typedef!(int[2], int[2].init, "InPixels");
>     alias InMeters = Typedef!(float[2], float[2].init, "InMeters");
>     alias SourceSizes = Typedef!(float[2], float[2].init, "SourceSizes");
>     alias PictureSize = SumType!(InPixels, InMeters, SourceSizes);

+1

We are using sumtype instead of std.variant exactly for that, attributes are not working with std.variant, and that's a show stopper.

/P

June 15, 2020
On Monday, 15 June 2020 at 04:08:14 UTC, Dukc wrote:
>
> Supporting all attributes definitely sounds good. OTOH your example isn't as DRY as with Taggedalgebraic:
>
> ```
> alias PictureSize = TaggedUnion!PictureSize_;
> union PictureSize_
> {   int[2] inPixels;
>     float[2] inMeters;
>     float[2] inSourceSizes;
> }
> ```
>
> In essence, the problem is that I want an union with a customizable tag, not an afterwards defined "base class" for the types. I'd check Atila's library first for the latter. But I definitely could adapt `SumType` for my use with some extra wrapping.

Personally I would say it is more DRY, because there's no need to declare a superfluous `union` type for your tagged version to "inherit" from. But really this is just a matter of preference.

I'm not sure what you mean by 'base class.' Are you referring to the lack of built-in support for named members? It would not be terribly difficult to add a syntax for named SumType members similar to std.typecons.Tuple, so that you could write

SumType!(
    int[2], "InPixels",
    float[2], "InMeters",
    float[2], "InSourceSizes"
)

...and have SumType take care of all the `Typedef` stuff for you. So far I've held off on it because I figured it was easy enough already to do by hand, but if this is a feature that a lot of people want, I can certainly add it.
June 15, 2020
On 6/15/20 2:27 AM, Paolo Invernizzi wrote:
> On Sunday, 14 June 2020 at 18:04:57 UTC, Paul Backus wrote:
>> On Sunday, 14 June 2020 at 17:31:32 UTC, Dukc wrote:
>>> [...]
>>
>> FYI, SumType works with nothrow and @nogc, and can solve all of your other problems with std.variant as well. :)
>>
>> Duplicate types are not supported out-of-the-box, but can very easily be accomplished using `std.typecons.Typedef`:
>>
>>     alias InPixels = Typedef!(int[2], int[2].init, "InPixels");
>>     alias InMeters = Typedef!(float[2], float[2].init, "InMeters");
>>     alias SourceSizes = Typedef!(float[2], float[2].init, "SourceSizes");
>>     alias PictureSize = SumType!(InPixels, InMeters, SourceSizes);
> 
> +1
> 
> We are using sumtype instead of std.variant exactly for that, attributes are not working with std.variant, and that's a show stopper.

I have switched mysql-native to using TaggedAlgebraic specifically because Variant does not support @safe.

I agree with most of the stuff in this thread. What I would like to see is:

a) Algebraic should be more supportive of merging types (probably don't depend on Variant guts).
b) Variant should provide a mechanism to restrict all calls on it to conform to specified attributes. e.g. I should be able to declare a SafeVariant which can only be assigned to types that support safe operations.

Note that even with TaggedAlgebraic I had to add a safety feature to ensure everything was @safe: https://github.com/s-ludwig/taggedalgebraic/pull/40

Note that a big user of Variant (and rightfully so) is std.concurrency. You can look at a lot of std.concurrency complaints to find deficiencies with Variant.

-Steve
June 15, 2020
On Saturday, 13 June 2020 at 19:10:04 UTC, Andrei Alexandrescu wrote:
> I was curious about collecting a list of grievances about Variant. It's the oldest piece of generic code in std, and it predates a lot of good language additions.
>
> So what's wrong with Variant? One thing I collected from a coworker is that it doesn't work with Windows DLLs, because in turn typeof() comparison does not work across Windows DLLs.
>
> What are other problems with it?

I don't recall ever having a need for Variant; BUT, I have often needed an sum type implementation.  The fact that Algebraic is implemented as a specialization of Variant (VariantN technically) has made it a non-starter for me.  Specifically, the overhead of how the type being stored is checked and retrieved seems super heavy-weight compared to a simple tagged union approach.  Last I checked (admittedly a while ago), it was not better-C compatible and sum types are the more common approach in the kind of code that needs to be better-C.

Fortunately, implementing a clean, featureful sum type is really easy and fun in D which is probably why there are quite a few implementations floating around out there.  That said, the D idiom which I generally write in eschews inheritance and classes generally and I think is fairly common, so strong standard library support would be helpful in preventing unnecessary drift and incompatibility; a quick search of code.dlang.com reveals these alternatives and I assume that there are many more unpublished (I think I have three or four implementations myself):

https://code.dlang.org/packages/sumtype
https://code.dlang.org/packages/tagged_union
https://code.dlang.org/packages/tag
https://code.dlang.org/packages/dadt
June 15, 2020
On Monday, 15 June 2020 at 12:41:03 UTC, Paul Backus wrote:
> I'm not sure what you mean by 'base class.' Are you referring to the lack of built-in support for named members? It would not be terribly difficult to add a syntax for named SumType members similar to std.typecons.Tuple, so that you could write

I understood correctly, SumType automatically implements the member functions that all the member types do. In that regard it becomes a kind of base class for all the types specified. Thats also what the `TaggedAlgebraic` types of the Taggedalgebraic package (as opposed to `TaggedUnion`s) does IIRC.

But as you can imagine, it isn't necessarily a good thing for my `PictureSize` example. Consider `aPictureSize[1] += 10;`. If I did that, it is unlikely that I wanted to add 10 to picture height, regardless of the units. More likely scenario is that I forgot to specify the units I'm assuming `PictureSize` to be in. Thus, I prefer a compiler error when it happens.



> ...and have SumType take care of all the `Typedef` stuff for you. So far I've held off on it because I figured it was easy enough already to do by hand, but if this is a feature that a lot of people want, I can certainly add it.

I think it's just about how you think about the type tag. If you think it just as an internal bookkeeper of what type is in, your current design is good. But if you want to base program logic directly on the tag value, then you get the opinions I have. Check Rust's `enum` types, they are a perfect example of my school of thought.

So if you want, you could do like Taggedalgebraic and have two types, one for each school. On the other hand, there is nothing wrong in just picking the audience and let others look for something else.

June 15, 2020
On Monday, 15 June 2020 at 16:06:15 UTC, Dukc wrote:
> On Monday, 15 June 2020 at 12:41:03 UTC, Paul Backus wrote:
>> I'm not sure what you mean by 'base class.' Are you referring to the lack of built-in support for named members? It would not be terribly difficult to add a syntax for named SumType members similar to std.typecons.Tuple, so that you could write
>
> I understood correctly, SumType automatically implements the member functions that all the member types do. In that regard it becomes a kind of base class for all the types specified. Thats also what the `TaggedAlgebraic` types of the Taggedalgebraic package (as opposed to `TaggedUnion`s) does IIRC.

SumType does not implement any member functions other than the ones listed in its documentation [1]: opAssign, opEquals, toString, and toHash.

I am curious how you arrived at this misconception. Is there a way I can improve SumType's documentation to make its behavior in this regard clearer?

[1] https://pbackus.github.io/sumtype/sumtype.SumType.html

>> ...and have SumType take care of all the `Typedef` stuff for you. So far I've held off on it because I figured it was easy enough already to do by hand, but if this is a feature that a lot of people want, I can certainly add it.
>
> I think it's just about how you think about the type tag. If you think it just as an internal bookkeeper of what type is in, your current design is good. But if you want to base program logic directly on the tag value, then you get the opinions I have. Check Rust's `enum` types, they are a perfect example of my school of thought.

In both Rust's `enum` types and SumType, you cannot access the tag directly. Instead, you must use pattern-matching.
June 15, 2020
On Monday, 15 June 2020 at 16:30:17 UTC, Paul Backus wrote:
>
> SumType does not implement any member functions other than the ones listed in its documentation [1]: opAssign, opEquals, toString, and toHash.
>
> I am curious how you arrived at this misconception.

By cutting corners when doing research. Sorry.

> Is there a way I can improve SumType's documentation to make its behavior in this regard clearer?

It's not documentations fault. But if you want to supersede Taggedalgebraic really hard, you can try convincing Mike to let you write a project highlight in the D blog, to raise awareness for thickskulls like me :D.

>
> In Rust's `enum` types you cannot access the tag directly.

Again bad research from my part. But it's something I want to do. Why? `final switch` statements. I may want to `return` or `break` directly from the switch, and in that case I can't use pattern matching without extra thinking. Well, on D anyway. I don't know about Rust.


June 15, 2020
On Saturday, 13 June 2020 at 19:10:04 UTC, Andrei Alexandrescu wrote:
> What are other problems with it?

It's not very useful?
Honestly I've never needed a Variant. But one time I used Algebraic, and even then changing it to a manual tagged union wasn't that bad.
June 16, 2020
On Monday, 15 June 2020 at 21:48:19 UTC, Dukc wrote:
>> Is there a way I can improve SumType's documentation to make its behavior in this regard clearer?
>
> It's not documentations fault. But if you want to supersede Taggedalgebraic really hard, you can try convincing Mike to let you write a project highlight in the D blog, to raise awareness for thickskulls like me :D.

That's an interesting idea. I'll look into it after the upcoming 1.0.0 release.

>> In Rust's `enum` types you cannot access the tag directly.
>
> Again bad research from my part. But it's something I want to do. Why? `final switch` statements. I may want to `return` or `break` directly from the switch, and in that case I can't use pattern matching without extra thinking. Well, on D anyway. I don't know about Rust.

If it's not too much trouble, can you give an example of the kind of thing you'd like to be able to do? I suspect it's possible with SumType, but it may not be obvious how, which makes it a good candidate for the documentation's "examples" section.