www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - variant visit not pure?

reply learner <learner nomail.com> writes:
Good morning,

Is there a reason why std.variant.visit is not inferring pure?

```
void test() pure {
     Algebraic!(int, string) alg;
     visit!( (string) => 0, (int) => 0)(alg);
}

Error: pure function test cannot call impure function 
test.visit!(VariantN!(16LU, int, string)).visit
```

Thank you
May 07 2020
next sibling parent reply Dukc <ajieskola gmail.com> writes:
On Thursday, 7 May 2020 at 09:22:28 UTC, learner wrote:
 Good morning,

 Is there a reason why std.variant.visit is not inferring pure?
I think `variant` will not infer any trributes. I'm not sure why. It could be some language limitation (that's the reason why `std.range.enumerate` does not infer attributes for example). Or it could be just badly implemented. Either way, there are DUB packages that are better in this (and other) regards. I recommend Taggedalgebraic[1]. [1] https://code.dlang.org/packages/taggedalgebraic
May 07 2020
parent Dukc <ajieskola gmail.com> writes:
On Thursday, 7 May 2020 at 10:21:26 UTC, Dukc wrote:
 that's the reason why `std.range.enumerate` does not infer 
 attributes for example
This was wrong. `enumerate` can infer. It's `lockstep` that cannot.
May 08 2020
prev sibling next sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Thursday, 7 May 2020 at 09:22:28 UTC, learner wrote:
 Good morning,

 Is there a reason why std.variant.visit is not inferring pure?

 ```
 void test() pure {
     Algebraic!(int, string) alg;
     visit!( (string) => 0, (int) => 0)(alg);
 }

 Error: pure function test cannot call impure function 
 test.visit!(VariantN!(16LU, int, string)).visit
 ```
std.variant.Algebraic is essentially a std.variant.Variant in different clothes. Variant is very flexible, and this comes at a cost (and isn't used in Algebraic, meaning you pay for things you don't use). Like Dukc said, you might be better off with Taggedalgebraic or SumType (https://code.dlang.org/packages/sumtype). Variant uses runtime type information to hold *any* type. Since Algebraic specifically only holds a few types, all the framework that's in place for Variant is wasted on Algebraic, and makes it less useful and less performant. -- Simen
May 07 2020
parent reply learner <learner nomail.com> writes:
On Thursday, 7 May 2020 at 10:41:01 UTC, Simen Kjærås wrote:
 On Thursday, 7 May 2020 at 09:22:28 UTC, learner wrote:
 Good morning,

 Is there a reason why std.variant.visit is not inferring pure?

 ```
 void test() pure {
     Algebraic!(int, string) alg;
     visit!( (string) => 0, (int) => 0)(alg);
 }

 Error: pure function test cannot call impure function 
 test.visit!(VariantN!(16LU, int, string)).visit
 ```
std.variant.Algebraic is essentially a std.variant.Variant in different clothes. Variant is very flexible, and this comes at a cost (and isn't used in Algebraic, meaning you pay for things you don't use). Like Dukc said, you might be better off with Taggedalgebraic or SumType (https://code.dlang.org/packages/sumtype). Variant uses runtime type information to hold *any* type. Since Algebraic specifically only holds a few types, all the framework that's in place for Variant is wasted on Algebraic, and makes it less useful and less performant. -- Simen
Thank you Simon and Dukc, I've find this: https://issues.dlang.org/show_bug.cgi?id=16662 So, it seems that Phobos isn't in a good shape ... what a pity!
May 07 2020
parent Dukc <ajieskola gmail.com> writes:
On Thursday, 7 May 2020 at 13:17:21 UTC, learner wrote:
 I've find this: https://issues.dlang.org/show_bug.cgi?id=16662
Hmm, that explains why it can't infer attributes. An unlimited variant could contain an object, and using it might or might not be <insert attribute here>. Of course, it could still infer the attribute for algebraic types were the wrapper a bit smarter. But `Algebraic` is inferior to the DUB packages anyway. Bad performance like Simen said, and can always be `null` regardless of requested types. With Taggedalgebraic, you can insert `Void` to allowed types if you want `null` value but you don't have it just because.
May 07 2020
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/7/20 5:22 AM, learner wrote:
 Good morning,
 
 Is there a reason why std.variant.visit is not inferring pure?
 
 ```
 void test() pure {
      Algebraic!(int, string) alg;
      visit!( (string) => 0, (int) => 0)(alg);
 }
 
 Error: pure function test cannot call impure function 
 test.visit!(VariantN!(16LU, int, string)).visit
 ```
 
 Thank you
Because VariantN (the base of Algebraic) can literally hold anything, it cannot be pure, safe, nothrow, nogc. As others have recommended, I suggest using TaggedAlgebraic. I recently have been using it to create an algebraic type to hold a MYSQL value, so I can migrate the mysql-native library to be safe (mysql-native currently uses Variant for everything). I added a special UDA to TaggedAlgebraic, so you can guarantee only safe calls are allowed (for instance, if it can hold a pointer and an int, then opBinary!"+" can be marked as safe if the operation fails when it's a pointer). TaggedAlgebraic could probably do the same for pure, but not sure about nothrow and nogc, since it uses exceptions when things aren't valid. -Steve
May 07 2020
next sibling parent reply Ben Jones <fake fake.fake> writes:
On Thursday, 7 May 2020 at 14:53:10 UTC, Steven Schveighoffer 
wrote:

 As others have recommended, I suggest using TaggedAlgebraic. I 
 recently have been using it to create an algebraic type to hold 
 a MYSQL value, so I can migrate the mysql-native library to be 
  safe (mysql-native currently uses Variant for everything).

 -Steve
I've been using SumType... What are the main differences between it and TaggedAlgebraic?
May 07 2020
next sibling parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 7 May 2020 at 15:36:36 UTC, Ben Jones wrote:
 On Thursday, 7 May 2020 at 14:53:10 UTC, Steven Schveighoffer 
 wrote:

 As others have recommended, I suggest using TaggedAlgebraic. I 
 recently have been using it to create an algebraic type to 
 hold a MYSQL value, so I can migrate the mysql-native library 
 to be  safe (mysql-native currently uses Variant for 
 everything).

 -Steve
I've been using SumType... What are the main differences between it and TaggedAlgebraic?
As far as I can tell, there are two main differences: 1. TaggedAlgebraic has some convenient operator overloads that can assert at runtime if called improperly (i.e., when the contained type does not support the operation). SumType never asserts at runtime, and instead requires you to use `match` for these operations to ensure that they are only performed on the appropriate types. 2. TaggedAlgebraic requires you to declare a union type as a "base", whereas SumType takes the list of member types directly as template arguments. If you want more detailed information, both have online documentation: TaggedAlgebraic: https://vibed.org/api/taggedalgebraic.taggedalgebraic/ SumType: https://pbackus.github.io/sumtype/sumtype.html
May 07 2020
prev sibling parent Dukc <ajieskola gmail.com> writes:
On Thursday, 7 May 2020 at 15:36:36 UTC, Ben Jones wrote:
 I've been using SumType... What are the main differences 
 between it and TaggedAlgebraic?
I have not used the the algebraic type of Taggedalgebraic tbh, but it also has a tagged union type that I have good experiences with. Unlike Phobos algebraic or SumType, it can have multiple fields of same type that are still separate by the tag value. Also unlike the two others I mentioned, you can handily define a `Void` field (or many of them) if you want special values for the tag that don't come with a value. In essence, `Taggedalgebraic.TaggedUnion` it's the D equivalent of Rust `enum`[1]. 1: https://doc.rust-lang.org/book/ch06-00-enums.html
May 08 2020
prev sibling parent reply learner <learner nomail.com> writes:
On Thursday, 7 May 2020 at 14:53:10 UTC, Steven Schveighoffer 
wrote:
 On 5/7/20 5:22 AM, learner wrote:
 [...]
Because VariantN (the base of Algebraic) can literally hold anything, it cannot be pure, safe, nothrow, nogc. As others have recommended, I suggest using TaggedAlgebraic. I recently have been using it to create an algebraic type to hold a MYSQL value, so I can migrate the mysql-native library to be safe (mysql-native currently uses Variant for everything). I added a special UDA to TaggedAlgebraic, so you can guarantee only safe calls are allowed (for instance, if it can hold a pointer and an int, then opBinary!"+" can be marked as safe if the operation fails when it's a pointer). TaggedAlgebraic could probably do the same for pure, but not sure about nothrow and nogc, since it uses exceptions when things aren't valid. -Steve
Modules of D standard library aren't in a good shape, if everyone suggests alternatives for a basic building block as variant. The types VariantN can hold are known at compile time, why can't it be specialized?
May 07 2020
parent Dukc <ajieskola gmail.com> writes:
On Thursday, 7 May 2020 at 20:12:03 UTC, learner wrote:
 Modules of D standard library aren't in a good shape, if 
 everyone suggests alternatives for a basic building block as 
 variant.
I don't think Variant as a whole is the problem, when one uses it as the infinite variant it does fairly much what one can expect. The finite-field specialization of it is the one that's badly implemented.
 The types VariantN can hold are known at compile time, why 
 can't it be specialized?
It could, probably. This shows the biggest weakness (and strength) of D development: It's voluntary, so people work on that they happen to want to. That makes it unevenly developed compared to financially backed projects. We have both plenty of cool & rare features and lack of many relatively basic ones at the same time.
May 08 2020