www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Scripting with Variant from std.variant: parameter passing

reply Carl Sturtivant <sturtivant gmail.com> writes:
It seems I cannot pass e.g. an int argument to a Variant function 
parameter. What's the simplest way to work around this 
restriction?
Feb 02
next sibling parent Danilo <codedan aol.com> writes:
On Friday, 2 February 2024 at 08:22:42 UTC, Carl Sturtivant wrote:
 It seems I cannot pass e.g. an int argument to a Variant 
 function parameter. What's the simplest way to work around this 
 restriction?
Just tell the compiler clearly what you want. ```d import std; void f(Variant x) { writeln(x); } void main() { f( Variant(42) ); f( Variant(2.5) ); f( Variant("Hi!") ); } ```
Feb 02
prev sibling next sibling parent reply Anonymouse <zorael gmail.com> writes:
On Friday, 2 February 2024 at 08:22:42 UTC, Carl Sturtivant wrote:
 It seems I cannot pass e.g. an int argument to a Variant 
 function parameter. What's the simplest way to work around this 
 restriction?
The easiest thing would be to actually pass it a `Variant` with `someFunction(Variant(myInt))`. The more-involved thing would be to write a template constrained to non-`Variants` that does the above for you. ```d auto someFunction(T)(T t) if (!is(T : Variant)) { return someFunction(Variant(t)); } auto someFunction(Variant v) { // ... } void main() { someFunction(42); someFunction("hello"); someFunction(3.14f); someFunction(true); someFunction(Variant(9001)); } ```
Feb 02
parent reply Danilo <codedan aol.com> writes:
On Friday, 2 February 2024 at 11:31:09 UTC, Anonymouse wrote:
 On Friday, 2 February 2024 at 08:22:42 UTC, Carl Sturtivant 
 wrote:
 It seems I cannot pass e.g. an int argument to a Variant 
 function parameter. What's the simplest way to work around 
 this restriction?
The easiest thing would be to actually pass it a `Variant` with `someFunction(Variant(myInt))`. The more-involved thing would be to write a template constrained to non-`Variants` that does the above for you. ```d auto someFunction(T)(T t) if (!is(T : Variant)) { return someFunction(Variant(t)); } auto someFunction(Variant v) { // ... } void main() { someFunction(42); someFunction("hello"); someFunction(3.14f); someFunction(true); someFunction(Variant(9001)); } ```
To be honest, this doesn't make sense. `if (!is(T : Variant))` returns true for inputs like 42, "hello", 3.14f, but the input is not a Variant but a random type. Yes, it's nice that it works in this case. It's just not logical, it doesn't make sense because 42 just simply isn't a Variant, it's an `int`.
Feb 03
parent Anonymouse <zorael gmail.com> writes:
On Saturday, 3 February 2024 at 08:04:40 UTC, Danilo wrote:
 To be honest, this doesn't make sense.

 `if (!is(T : Variant))` returns true for inputs like 42, 
 "hello", 3.14f, but the input is not a Variant but a random 
 type.

 Yes, it's nice that it works in this case. It's just not 
 logical, it doesn't make sense because 42 just simply isn't a 
 Variant, it's an `int`.
I read it several times but I don't think I understand what you mean. The constraint `if (!is(T : Variant))` is true for every input that is not a `Variant`, yes. The point of it is to let calls to `someFunction(myVariant)` resolve to the non-templated `auto someFunction(Variant)`. Is your argument that it's wrong to assume an `int` *can be* wrapped in a `Variant`, because it isn't one? That in turn doesn't make sense -- your example does the same, just explicitly. ```d void main() { f( Variant(42) ); f( Variant(2.5) ); f( Variant("Hi!") ); } ``` How is this different from the following? ```d void main() { (v){ f(Variant(v)); }(42); (v){ f(Variant(v)); }(2.5); (v){ f(Variant(v)); }("Hi!"); } ``` And how is that different from the following? ```d void main() { auto g(T)(T t) { f(Variant(t)); } g(42); g(2.5); g("Hi!"); } ``` Which is in what way different from the following? ```d auto g(T)(T t) if (!is(T : Variant)) { return f(Variant(t)); } auto f(Variant v) { // ... } void main() { g(42); g("hello"); g(3.14f); g(true); } ``` And how is that not the same as my original example?
Feb 03
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On Friday, 2 February 2024 at 08:22:42 UTC, Carl Sturtivant wrote:
 It seems I cannot pass e.g. an int argument to a Variant 
 function parameter. What's the simplest way to work around this 
 restriction?
You'd have to implement the function that accepts the parameters and wraps in a Variant. This is the best I can come up with, which should be copy/pasteable to other shims: ```d void foo(Variant x, Variant y) { ... } import std.meta : allSatisfy; enum isVariant(T) = is(T == Variant); // this is going to suck at CTFE but... string argsAsVariants(size_t count) { import std.format; import std.range; import std.alglorithm; import std.array; return iota(count).map!(i => format("Variant(args[%s])", i).join(","); } // shim auto foo(Args...)(Args args) if (!allSatisfy!(isVariant, Args)) { mixin("return foo(", argsAsVariants(args.length), ");"); } ``` -Steve
Feb 02
parent reply Carl Sturtivant <sturtivant gmail.com> writes:
On Friday, 2 February 2024 at 19:22:22 UTC, Steven Schveighoffer 
wrote:
 ```d
 void foo(Variant x, Variant y) { ... }

 import std.meta : allSatisfy;

 enum isVariant(T) = is(T == Variant);

 // this is going to suck at CTFE but...
 string argsAsVariants(size_t count)
 {
    import std.format;
    import std.range;
    import std.alglorithm;
    import std.array;
    return iota(count).map!(i => format("Variant(args[%s])", 
 i).join(",");
 }

 // shim
 auto foo(Args...)(Args args) if (!allSatisfy!(isVariant, Args))
 {
     mixin("return foo(", argsAsVariants(args.length), ");");
 }
 ```
Thanks for this idea. I'll work on it.
 -Steve
Feb 02
parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 2 February 2024 at 20:28:50 UTC, Carl Sturtivant wrote:
 On Friday, 2 February 2024 at 19:22:22 UTC, Steven 
 Schveighoffer wrote:
 ```d
 // shim
 auto foo(Args...)(Args args) if (!allSatisfy!(isVariant, Args))
 {
     mixin("return foo(", argsAsVariants(args.length), ");");
 }
 ```
Thanks for this idea. I'll work on it.
Another variation on the same theme: ```d void foo(Variant x, Variant y) { import std.stdio: writeln; writeln("x = ", x); writeln("y = ", y); } /// map over a variadic argument list template mapArgs(alias fun) { auto mapArgs(Args...)(auto ref Args args) { import std.typecons: tuple; import core.lifetime: forward; import std.meta: Map = staticMap; auto ref mapArg(alias arg)() { return fun(forward!arg); } return tuple(Map!(mapArg, args)); } } import std.variant: Variant; import std.meta: allSatisfy; enum isVariant(T) = is(T == Variant); auto foo(Args...)(Args args) if (!allSatisfy!(isVariant, Args)) { return .foo(mapArgs!Variant(args).expand); } void main() { foo(123, 456); foo("hello", "world"); } ```
Feb 02
parent Carl Sturtivant <sturtivant gmail.com> writes:
On Friday, 2 February 2024 at 20:58:12 UTC, Paul Backus wrote:
 Another variation on the same theme:
 ```d
 /// map over a variadic argument list
 template mapArgs(alias fun)
 {
 	auto mapArgs(Args...)(auto ref Args args)
 	{
 		import std.typecons: tuple;
 		import core.lifetime: forward;
 		import std.meta: Map = staticMap;

 		auto ref mapArg(alias arg)()
 		{
 			return fun(forward!arg);
 		}

 		return tuple(Map!(mapArg, args));
 	}
 }

 import std.variant: Variant;
 import std.meta: allSatisfy;

 enum isVariant(T) = is(T == Variant);

 auto foo(Args...)(Args args)
     if (!allSatisfy!(isVariant, Args))
 {
     return .foo(mapArgs!Variant(args).expand);
 }
 ```
Thanks, will study the library machinery you used here.
Feb 03