www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Variable "i" can not be read at compile time

reply data pulverizer <data.pulverizer gmail.com> writes:
Hi all,

I'm getting the error:

```
Error: variable i cannot be read at compile time
Error: template instance 
script.runKernelBenchmarks!(Tuple!(DotProduct!float, 
Gaussian!float, Polynomial!float, Exponential!float, Log!float, 
Cauchy!float, Power!float, Wave!float, Sigmoid!float)) error 
instantiating
```

When I run ...

```
...
auto runKernelBenchmarks(KS)(KS kernels, long[] n, bool verbose = 
true)
{
   auto tmp = bench(kernels[0], n, verbose);
   alias R = typeof(tmp);
   R[] results = new R[kernels.length];
   results[0] = tmp;
   for(size_t i = 1; i < results.length; ++i)
   {
     results[i] = bench(kernels[i], n, verbose);
   }
   return results;
}

void main()
{
   alias T = float;
   auto kernels = tuple(DotProduct!(T)(),   Gaussian!(T)(1), 
Polynomial!(T)(2.5f, 1),
                        Exponential!(T)(1), Log!(T)(3),      
Cauchy!(T)(1),
                        Power!(T)(2.5f),    Wave!(T)(1),     
Sigmoid!(T)(1, 1));
   string[] kernelNames = ["DotProduct",  "Gaussian", "Polynomial",
                        "Exponential", "Log",      "Cauchy",
                        "Power",       "Wave",     "Sigmoid"];
   long[] n = [100L, 500L, 1000L];
   auto results = runKernelBenchmarks(kernels, n);
   writeln("Results: ", results);
}
```

Thanks
May 24 2020
parent reply ag0aep6g <anonymous example.com> writes:
On 24.05.20 18:34, data pulverizer wrote:
 I'm getting the error:
 
 ```
 Error: variable i cannot be read at compile time
 Error: template instance 
 script.runKernelBenchmarks!(Tuple!(DotProduct!float, Gaussian!float, 
 Polynomial!float, Exponential!float, Log!float, Cauchy!float, 
 Power!float, Wave!float, Sigmoid!float)) error instantiating
 ```
 
 When I run ...
 
 ```
 ...
 auto runKernelBenchmarks(KS)(KS kernels, long[] n, bool verbose = true)
 {
    auto tmp = bench(kernels[0], n, verbose);
    alias R = typeof(tmp);
    R[] results = new R[kernels.length];
    results[0] = tmp;
    for(size_t i = 1; i < results.length; ++i)
    {
      results[i] = bench(kernels[i], n, verbose);
    }
    return results;
 }
 
 void main()
 {
    alias T = float;
    auto kernels = tuple(DotProduct!(T)(),   Gaussian!(T)(1), 
 Polynomial!(T)(2.5f, 1),
                         Exponential!(T)(1), Log!(T)(3),
Cauchy!(T)(1),
                         Power!(T)(2.5f),   
Wave!(T)(1), Sigmoid!(T)(1, 
 1));
    string[] kernelNames = ["DotProduct",  "Gaussian", "Polynomial",
                         "Exponential", "Log",     
"Cauchy",
                         "Power",      
"Wave",     "Sigmoid"];
    long[] n = [100L, 500L, 1000L];
    auto results = runKernelBenchmarks(kernels, n);
    writeln("Results: ", results);
 }
 ```
Since `kernel` is a `Tuple`, you can only access it with compile-time constant indices. But your loop variable `i` is not a compile-time constant, it's being calculated at run time. What's more, it depends on `results.length` which is also not a compile-time constant. But `results.length` is the same as `kernels.length`. And being the length of a `Tuple`, that one is a compile-time constant. So you can rewrite your loop as a `static foreach` (which is evaluated during compile-time) using `kernels.length` instead of `results.length`: static foreach (i; 1 .. kernels.length) { results[i] = bench(kernels[i], n, verbose); }
May 24 2020
parent reply data pulverizer <data.pulverizer gmail.com> writes:
On Sunday, 24 May 2020 at 16:57:54 UTC, ag0aep6g wrote:
 On 24.05.20 18:34, data pulverizer wrote:
 Since `kernel` is a `Tuple`, you can only access it with 
 compile-time constant indices.

 But your loop variable `i` is not a compile-time constant, it's 
 being calculated at run time. What's more, it depends on 
 `results.length` which is also not a compile-time constant. But 
 `results.length` is the same as `kernels.length`. And being the 
 length of a `Tuple`, that one is a compile-time constant.

 So you can rewrite your loop as a `static foreach` (which is 
 evaluated during compile-time) using `kernels.length` instead 
 of `results.length`:

 static foreach (i; 1 .. kernels.length)
 {
     results[i] = bench(kernels[i], n, verbose);
 }
Thank you very much. I though that if I used a `static foreach` loop D would attempt to run the calculation `bench()` at compile time rather than at run time but it doesn't which is good. So `static foreach` allows you to index at compile time and if its scope runs at run time it is run time and if at compile time it is compile time evaluated?
May 24 2020
next sibling parent bauss <jj_1337 live.dk> writes:
On Sunday, 24 May 2020 at 17:13:23 UTC, data pulverizer wrote:
 On Sunday, 24 May 2020 at 16:57:54 UTC, ag0aep6g wrote:
 On 24.05.20 18:34, data pulverizer wrote:
 Since `kernel` is a `Tuple`, you can only access it with 
 compile-time constant indices.

 But your loop variable `i` is not a compile-time constant, 
 it's being calculated at run time. What's more, it depends on 
 `results.length` which is also not a compile-time constant. 
 But `results.length` is the same as `kernels.length`. And 
 being the length of a `Tuple`, that one is a compile-time 
 constant.

 So you can rewrite your loop as a `static foreach` (which is 
 evaluated during compile-time) using `kernels.length` instead 
 of `results.length`:

 static foreach (i; 1 .. kernels.length)
 {
     results[i] = bench(kernels[i], n, verbose);
 }
Thank you very much. I though that if I used a `static foreach` loop D would attempt to run the calculation `bench()` at compile time rather than at run time but it doesn't which is good. So `static foreach` allows you to index at compile time and if its scope runs at run time it is run time and if at compile time it is compile time evaluated?
You can see static foreach as unrolling a compile-time loop to a set of runtime-expressions. Ex. static foreach (i; 0 .. 10) { writeln(i); } Actually just becomes writeln(0); writeln(1); writeln(2); writeln(3); writeln(4); writeln(5); writeln(6); writeln(7); writeln(8); writeln(9); - It creates no scope, whatsoever either. However doing static foreach () {{ ... }} Will create a scope per iteration.
May 24 2020
prev sibling parent ag0aep6g <anonymous example.com> writes:
On 24.05.20 19:13, data pulverizer wrote:
 Thank you very much. I though that if I used a `static foreach` loop D 
 would attempt to run the calculation `bench()` at compile time rather 
 than at run time but it doesn't which is good. So `static foreach` 
 allows you to index at compile time and if its scope runs at run time it 
 is run time and if at compile time it is compile time evaluated?
`static foreach` gets unrolled at compile time. It doesn't affect how the body is handled. It's like copy-pasting the loop body n times in the source code. For example, this: int x = 0; static foreach (i; 0 .. 3) { x += f(i); } is the same this: int x = 0; x += f(0); x += f(1); x += f(2); It doesn't affect how `f` is being run. They're ordinary run-time calls either way. To evaluate the `f` calls during compilation you can use `enum` to trigger CTFE: int x = 0; enum f0 = f(0); /* CTFE */ x += f0; enum f1 = f(1); /* CTFE */ x += f1; enum f2 = f(2); /* CTFE */ x += f2; or with `static foreach`: int x = 0; static foreach (i; 0 .. 3) {{ enum e = f(i); x += e; }} Notice the extra set of braces. It's just adding a scope. Without that, the different `e`s would clash with each other.
May 24 2020