Printing Tuple!(...)[] using for loop?

Steven Schveighoffer schveiguy at gmail.com
Fri Jul 2 14:09:59 UTC 2021


On 7/2/21 12:21 AM, Kirill wrote:
> I have a `Tuple!(string, ..., string)[] data` that I would like to print 
> out:
> `a   b   c`
> `1   2   3`
> `4   5   6`
> 
>      Furthermore, I want to be able to print any N rows and M columns of 
> that table. For instance:
>          `b   c`
>          `2   3`
>          or
>          `1   2   3`
>          `4   5   6`
> 
> I am using for loops for that:
> 
>          // inside some function(rows, cols):
>          immutable startFromRow = ...;
>          immutable endWithRow = ...;
>          immutable startFromCol = ...;
>          immutable endWithCol = ...;
> 
>          // print data
>          for(size_t i = startFromRow; i < endWithRow; i++) {
>              for(size_t j = startFromCol; j < endWithCol; j++) {
>                  writef("%s", data[i][j]);
>              }
>              writef("\n");
>          }
> 
> And the compiler puts out the following:
> `Error: variable 'j' cannot be read at compile time`
> 
> I tried `data[i].expand[j]`, but the same error occurs anyway.
> 
> I have two questions:
> 1. How do I print the contents of a Tuple using for loops? Or any other 
> method?
> 2. What am I missing? How does it actually work under the hood?

So a tuple is really like an unnamed group of variables.

A `Tuple!(int, int, int)` is really like three ints that are all 
separate variables. It's just that they are named via the group. It is 
NOT like an array, it's more like a struct with fields that have indexes 
instead of names.

In order to print them in a loop, based on *runtime* data, you need to 
bridge the gap between runtime and compile time. Why? Because a Tuple 
does not necessarily contain the same types for every value, so `tup[0]` 
might have a different type than `tup[1]`. Because D is strongly-typed, 
you need to access these with *compile-time* indexes, so it knows what 
type you are using.

Imagine you have a struct, and you want to use a runtime string to 
access a given field. This is essentially the same, except it's an index 
and not a name.

A typical way to bridge the gap is to use a switch to validate the 
runtime variable, and then use the compile-time equivalalent to actually 
get the data.

For example, you could write a function like:

```d
void printItem(Tuple!(...) vals, size_t index)
{
theswitch:
     final switch(index)
     {
        static foreach(ctIdx; 0 .. vals.length) {
             case ctIdx: writeln(vals[ctIdx]);
             break theswitch;
        }
     }
}
```

Now, if you want to just print them in order, without any runtime 
details, you can just use foreach on a tuple and it works (the foreach 
variables are compile-time determined).

-Steve


More information about the Digitalmars-d-learn mailing list