Thread overview
Manipulating alias sequences
Jul 15, 2019
Ben Ogles
Jul 15, 2019
Stefan Koch
Jul 15, 2019
Ben Ogles
Jul 15, 2019
Paul Backus
Jul 15, 2019
Ben Ogles
July 15, 2019
I have written a simple function that can call another function over integral types with random arguments:

auto rnd = Random(42);

auto rand_integral(T)() {
  return uniform(T.min, T.max, rnd);
}

auto call_with_rand(alias fun)() {
  fun(staticMap!(get_rand_integral, Parameters!fun));
}

Now I want to extend it so that a caller can specify the values of only some of the parameters. I tried using a static foreach instead of the staticMap function. But I can't modify AliasSeq values.

alias args = AliasSeq!(0, 0);
static foreach (idx, val; args) {
  static if (user_defined_function_exists_for_arg!(idx)) {
    args[idx] = user_defined_function(); // cannot modify tuple
  } else {
    args[idx] = gen_rand_integral!(typeof(val)); // cannot modify tuple
  }
}

How do I build up an argument tuple at compile time where some values are randomly generated and others are given through some user defined function (most likely automatically discovered by a naming convention)?

July 15, 2019
On Monday, 15 July 2019 at 13:40:29 UTC, Ben Ogles wrote:
> I have written a simple function that can call another function over integral types with random arguments:
>
> [...]

You cannot. meta-programming and compile-time evaluation are supposed to be deterministic,
and hence cannot take random values.

July 15, 2019
On Monday, 15 July 2019 at 14:15:41 UTC, Stefan Koch wrote:
> On Monday, 15 July 2019 at 13:40:29 UTC, Ben Ogles wrote:
>> I have written a simple function that can call another function over integral types with random arguments:
>>
>> [...]
>
> You cannot. meta-programming and compile-time evaluation are supposed to be deterministic,
> and hence cannot take random values.

Sorry, I wasn't clear. The code I wrote does not actually _produce_ the random values at compile time. It is just a template that evaluates to a function call where each argument is given as `gen_rand_integral()`. So if I call

call_with_rand!(add)();

It will expand to


add(gen_rand_integral!(int)(), gen_rand_integral!(int)());

But I want a way to expand this to

add(gen_rand_integral!(int)(), user_defined_generator!(int)());

July 15, 2019
On Monday, 15 July 2019 at 13:40:29 UTC, Ben Ogles wrote:
> Now I want to extend it so that a caller can specify the values of only some of the parameters. I tried using a static foreach instead of the staticMap function. But I can't modify AliasSeq values.
>
> alias args = AliasSeq!(0, 0);
> static foreach (idx, val; args) {
>   static if (user_defined_function_exists_for_arg!(idx)) {
>     args[idx] = user_defined_function(); // cannot modify tuple
>   } else {
>     args[idx] = gen_rand_integral!(typeof(val)); // cannot modify tuple
>   }
> }
>
> How do I build up an argument tuple at compile time where some values are randomly generated and others are given through some user defined function (most likely automatically discovered by a naming convention)?

Use a run-time Tuple instead of an AliasSeq:

import std.typecons;
auto args = tuple(0, 0);
static foreach (idx, val; args) {
    static if (user_defined_function_exists_for_arg!idx) {
        args[idx] = user_defined_function();
    } else {
        args[idx] = gen_random_integral!(typeof(val));
    }
}

Then use `fun(args.expand)` to pass the members of the tuple as separate arguments to `fun`.
July 15, 2019
On Monday, 15 July 2019 at 14:50:20 UTC, Paul Backus wrote:
> Use a run-time Tuple instead of an AliasSeq:
>
> import std.typecons;
> auto args = tuple(0, 0);
> static foreach (idx, val; args) {
>     static if (user_defined_function_exists_for_arg!idx) {
>         args[idx] = user_defined_function();
>     } else {
>         args[idx] = gen_random_integral!(typeof(val));
>     }
> }
>
> Then use `fun(args.expand)` to pass the members of the tuple as separate arguments to `fun`.

Amazing, this works great! Thanks.