Thread overview
Printing Tuple!(...)[] using for loop?
Jul 02, 2021
Kirill
Jul 02, 2021
Alexandru Ermicioi
Jul 02, 2021
Bastiaan Veelo
July 02, 2021

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?

Thanks in advance. Any help is greatly appreciated.

July 02, 2021

On Friday, 2 July 2021 at 04:21:24 UTC, Kirill wrote:

>

...

  1. use static foreach for tuple loop.
  2. start column and end column should be known at compile time. Either make them immutable, or as enum constant, or pass them as an template argument.

Tuple is basically a wrapper over built in tuple support from D. Check it's insides to se how it is done. So to index a field in a tuple you need to know which field you want to access at compile time since, each field in a tuple has different size, and cannot be indexed at runtime easily.

Best regards,
Alexandru.

July 02, 2021

On Friday, 2 July 2021 at 04:21:24 UTC, Kirill wrote:

>

I have a Tuple!(string, ..., string)[] data

If there are only strings in the tuple, it could be simplified by making it a static array of strings instead. The compile-time index issue would go away.

—Bastiaan

July 02, 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:

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