www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Is std.variant.visit not nogc?

reply helxi <brucewayneshit gmail.com> writes:
import std.variant, core.stdc.stdio;

Algebraic!(T, string) fib_nth(T)(T n)
{
     return n % 15
                 ? n % 5
                     ? n % 3
                         ? Algebraic!(T, string)(n)
                         : Algebraic!(T, string)("Fizz")
                     : Algebraic!(T, string)("Buzz")
                 : Algebraic!(T, string)("Fizzbuzz");
}

void main()  nogc
{
     foreach (i; 1 .. 101)
     {
         fib_nth(i).visit!(
             (string s) => printf("%s\n", s.ptr),
             (int n) => printf("%i\n", n)
         );
     }
}


Complains source/app.d(18,19): Error:  nogc function D main 
cannot call non- nogc function std.variant.visit!(function 
(string s) => printf("%s\x0a", cast(immutable(char)*)s), function 
(int n) => printf("%i\x0a", n)).visit!(VariantN!(16LU, int, 
string)).visit
/usr/bin/dmd failed with exit code 1.


If so, is there a way to emulate `visit` in a  nogc setting?
Apr 08 2018
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 9 April 2018 at 03:20:58 UTC, helxi wrote:
 Is std.variant.visit not  nogc?
These error messages REALLY need to be fixed. visit, being a template, is nogc or not based on the arguments passed to it as well as its own body, so while the error messages point to visit itself, these are frequently actually caused the predicate your pass. ....well, in this case, it is actually visit itself. phobos/std/variant.d(2464): Error: nogc function std.variant.visitImpl!(true, VariantN!(8u, int, string), function (string s) => printf("%s\x0a", cast(immutable(char)*)s), function (int n) => printf("%i\x0a", n)).visitImpl cannot call non- nogc constructor std.variant.VariantException.this phobos/std/variant.d(2469): Error: nogc function std.variant.visitImpl!(true, VariantN!(8u, int, string), function (string s) => printf("%s\x0a", cast(immutable(char)*)s), function (int n) => printf("%i\x0a", n)).visitImpl cannot call non- nogc function std.variant.VariantN!(8u, int, string).VariantN.peek!int.peek phobos/std/variant.d(2469): Error: nogc function std.variant.visitImpl!(true, VariantN!(8u, int, string), function (string s) => printf("%s\x0a", cast(immutable(char)*)s), function (int n) => printf("%i\x0a", n)).visitImpl cannot call non- nogc function std.variant.VariantN!(8u, int, string).VariantN.peek!string.peek phobos/std/variant.d(2173): Error: template instance `std.variant.visitImpl!(true, VariantN!(8u, int, string), function (string s) => printf("%s\x0a", cast(immutable(char)*)s), function (int n) => printf("%i\x0a", n))` error instantiating Ugh, so unreadable even on this level, but at least the actual information is there: std.variant.VariantException.this is not marked nogc (but it prolly could be) VariantN.peek is not nogc because it calls Object.opEquals... which is broken af, sadly, but can probably be fixed for this case by marking TypeInfo.opEquals nogc. I think the peek one is going to be the harder one to work around since any reimplementation of peek is probably going to still call it... though MAYBE you can use `!is` instead of `!=`... and any reimplementation of visit needs to check types. But if you wanna try to work around it, I would copy the visitImpl and visit functions out of std.variant and do some adjustments, then call your version instead (which will be fairly easy btw since they are already UFCS). FYI: the way I got these error messages was to go into the Phobos source and add nogc to the lowest level template in the instantiation chain. Then just recompile your program - no need to recompile Phobos itself since they are templates. I wish the error messages would just do this for you (simulate nogc at the second-highest level) to keep you from having to edit it yourself just to know what it is.
Apr 08 2018
parent reply Hasen Judy <hasen.judy gmail.com> writes:
On Monday, 9 April 2018 at 03:41:17 UTC, Adam D. Ruppe wrote:
 On Monday, 9 April 2018 at 03:20:58 UTC, helxi wrote:

 visit, being a template, is  nogc or not based on the arguments 
 passed to it as well as its own body, so while the error 
 messages point to visit itself, these are frequently actually 
 caused the predicate your pass.

 [....]

 std.variant.VariantException.this is not marked  nogc (but it 
 prolly could be)

 VariantN.peek is not  nogc because it calls Object.opEquals... 
 which is broken af, sadly, but can probably be fixed for this 
 case by marking TypeInfo.opEquals nogc.
IMO, this is one more reason why sum-types should be built into the language compiler, instead of being implemented in user-space.
Apr 09 2018
parent reply Chris Katko <ckatko gmail.com> writes:
On Monday, 9 April 2018 at 07:02:50 UTC, Hasen Judy wrote:
 IMO, this is one more reason why sum-types should be built into 
 the language compiler, instead of being implemented in 
 user-space.
+1. Any time you have to "create" a fundamental feature in a language... from inside the language itself... you're going to have confusing error messages, and a huge uphill battle. Look at Boost. While I salute the effort put into those libraries, trying to "fix C++"... "from inside C++" is a fools errand. The upgraded multidimensional array code looks like this: typedef boost::multi_array<double, 3> array_type; typedef array_type::index index; array_type A(boost::extents[3][4][2]); as opposed to you know, in D: double [3][4][2] A; And the D version has useful error messages, small compile times, and it's still easier to read, reason about, and debug.
Apr 09 2018
parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 9 April 2018 at 07:07:58 UTC, Chris Katko wrote:
 On Monday, 9 April 2018 at 07:02:50 UTC, Hasen Judy wrote:
 IMO, this is one more reason why sum-types should be built 
 into the language compiler, instead of being implemented in 
 user-space.
+1. Any time you have to "create" a fundamental feature in a language... from inside the language itself... you're going to have confusing error messages, and a huge uphill battle.
I agree in general, but in this case it's actually completely doable. In fact, I've done it myself: check out 'sumtype' on code.dlang.org. You can replace 'Algebraic' with 'SumType' and 'visit' with 'match' in helxi's example, and everything Just Works™: import sumtype; import core.stdc.stdio; SumType!(T, string) fib_nth(T)(T n) { return n % 15 ? n % 5 ? n % 3 ? SumType!(T, string)(n) : SumType!(T, string)("Fizz") : SumType!(T, string)("Buzz") : SumType!(T, string)("Fizzbuzz"); } void main() nogc { foreach (i; 1 .. 101) { fib_nth(i).match!( (string s) => printf("%s\n", s.ptr), (int n) => printf("%i\n", n) ); } }
Apr 09 2018
parent reply helxi <brucewayneshit gmail.com> writes:
On Monday, 9 April 2018 at 15:59:32 UTC, Paul Backus wrote:
 On Monday, 9 April 2018 at 07:07:58 UTC, Chris Katko wrote:
 [...]
I agree in general, but in this case it's actually completely doable. In fact, I've done it myself: check out 'sumtype' on code.dlang.org. You can replace 'Algebraic' with 'SumType' and 'visit' with 'match' in helxi's example, and everything Just Works™: [...]
This isn't boxed by any chance, is it?
Apr 09 2018
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 10 April 2018 at 00:22:18 UTC, helxi wrote:
 On Monday, 9 April 2018 at 15:59:32 UTC, Paul Backus wrote:
 On Monday, 9 April 2018 at 07:07:58 UTC, Chris Katko wrote:
 [...]
I agree in general, but in this case it's actually completely doable. In fact, I've done it myself: check out 'sumtype' on code.dlang.org. You can replace 'Algebraic' with 'SumType' and 'visit' with 'match' in helxi's example, and everything Just Works™: [...]
This isn't boxed by any chance, is it?
Nope! It's just a tagged union, almost exactly the same as what you'd write by hand in C. You can take a look at the source yourself, if you're curious---it's actually pretty simple: https://github.com/pbackus/sumtype/blob/master/src/sumtype.d#L27
Apr 09 2018
parent reply aliak <something something.com> writes:
On Tuesday, 10 April 2018 at 03:48:25 UTC, Paul Backus wrote:
 Nope! It's just a tagged union, almost exactly the same as what 
 you'd write by hand in C. You can take a look at the source 
 yourself, if you're curious---it's actually pretty simple:

 https://github.com/pbackus/sumtype/blob/master/src/sumtype.d#L27
Awesome! this is a neat trick: union { AliasSeq!(T0, T1) values; } Is that usage documented somewhere, or is it somewhere in phobos maybe? Also, can Algebraic be fully replaced with this version then or is there some functionality that would stop it going through?
Apr 10 2018
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 10 April 2018 at 12:34:07 UTC, aliak wrote:
 Awesome!

 this is a neat trick:

 union
 {
   AliasSeq!(T0, T1) values;
 }

 Is that usage documented somewhere, or is it somewhere in 
 phobos maybe?

 Also, can Algebraic be fully replaced with this version then or 
 is there some functionality that would stop it going through?
It's called "type sequence instantiation", and it's documented in the "Compile-time Sequences" article [1] on dlang.org. I discovered it reading the source of the 'tagged_union' dub package [2]. It's not mentioned anywhere in the language spec, as far as I can tell. SumType should be capable of doing anything that Algebraic can do (if it's not, please open an issue on Github!), but it's not a drop-in replacement, and it's still a work in progress. Documentation for the current version (more or less) is available at http://sumtype.dpldocs.info/index.html. If there are any particular features you'd like to see, let me know, and I'll do my best to add them. [1] https://dlang.org/articles/ctarguments.html#type-seq-instantiation [2] https://github.com/Superstar64/tagged_union/blob/master/source/tagged_union.d
Apr 10 2018
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 4/10/18 12:59 PM, Paul Backus wrote:
 On Tuesday, 10 April 2018 at 12:34:07 UTC, aliak wrote:
 Awesome!

 this is a neat trick:

 union
 {
   AliasSeq!(T0, T1) values;
 }

 Is that usage documented somewhere, or is it somewhere in phobos maybe?

 Also, can Algebraic be fully replaced with this version then or is 
 there some functionality that would stop it going through?
It's called "type sequence instantiation", and it's documented in the "Compile-time Sequences" article [1] on dlang.org. I discovered it reading the source of the 'tagged_union' dub package [2]. It's not mentioned anywhere in the language spec, as far as I can tell.
Ooh! that's really cool. I've put AliasSeq of types into a struct, but never considered putting it into a union. This has a lot of potential when you want to auto-generate unions. Nice trick! -Steve
Apr 10 2018