Thread overview
Gotcha with const std.range.chunks
Jul 30, 2020
sportsracer
Jul 30, 2020
H. S. Teoh
Jul 31, 2020
sportsracer
July 30, 2020
Newcomer to the D language here. I was going to use `std.range.chunks` to get a two-dimensional, read-only view on data in one continuous array.

But was surprised to find that this code doesn't compile:

import std.range : chunks;
import std.stdio : writeln;

void main()
{
    int[] xs = new int[100];
    const chunked = xs.chunks(10);
    writeln(chunked[0][0]);
}

Error: mutable method std.range.Chunks!(int[]).Chunks.opIndex is not callable using a const object

… I'm not sure if this is due to my ignorance of the D type system, or could be considered missing functionality in the chunks helper function.
July 30, 2020
On Thu, Jul 30, 2020 at 06:52:42PM +0000, sportsracer via Digitalmars-d-learn wrote: [...]
>     int[] xs = new int[100];
>     const chunked = xs.chunks(10);
>     writeln(chunked[0][0]);
> }
> 
> Error: mutable method std.range.Chunks!(int[]).Chunks.opIndex is not
> callable using a const object

In order to iterate the chunks, you must be able to mutate the range object returned by .chunks. If it's const, then it's not mutable, and therefore it cannot be iterated.

If you want to protect the underlying data from mutation, create a const view of the data first, e.g., something like this:

	int[] xs = new int[100];
	const(int)[] constView = xs;
	auto chunked = constView.chunks(10); // N.B. mutable

The range itself will be mutable, but the elements will be const and not mutable through the range.


T

-- 
Why can't you just be a nonconformist like everyone else? -- YHL
July 31, 2020
Right, thank you! The range object needs to be mutated to be iterated on, that explains it.

Although it looks like the opIndex on this particular range could guarantee constness: https://github.com/dlang/phobos/blob/v2.093.0/std/range/package.d#L8099

Here's a longer code snippet that gives some context on why I thought I needed a const range object. This Matrix class would have the chunks range object stored as a private property, and use it in its opIndex to look up values. I wanted to add the const qualifier to the opIndex method, since it doesn't mutate the Matrix state, and that's what surfaced this error.


class Matrix(T)
{
    private {
        T[] data;
        Chunks!(T[]) view;
    }

    this(size_t width, size_t height)
    {
        this.data = new int[width * height];
        this.view = data.chunks(width);
    }

    T opIndex(size_t col, size_t row) /*const*/ // FIXME Can't be const because Chunks.opIndex isn't
    {
        return view[row][col];
    }
}

void main()
{
    auto matrix = new Matrix!int(10, 10);
    writeln(matrix[0, 0]);
}


Oh well, I'll try a different way!