Thread overview
Calling assumeSorted on const(std.container.Array)
March 25

I'm trying to call assumeSorted on a const(Array) using this code snippet:

void test(T)(const ref Array!T a)
{
    auto b = a[].assumeSorted;
    writeln(b);
}

void main() {
    Array!int a = [1, 5, 7, 8, 15, 100];
    test(a);
}

Unfortunately, I keep having a compilation error:
/dlang/dmd/linux/bin64/../../src/phobos/std/range/package.d(10871): Error: cannot modify struct instance result._input of type RangeT!(const(Array!int)) because it contains const or immutable members
/dlang/dmd/linux/bin64/../../src/phobos/std/range/package.d(10918): Error: cannot modify struct instance result._input of type RangeT!(const(Array!int)) because it contains const or immutable members
/dlang/dmd/linux/bin64/../../src/phobos/std/range/package.d(11500): Error: template instance std.range.SortedRange!(RangeT!(const(Array!int)), "a < b", SortedRangeOptions.assumeSorted) error instantiating
onlineapp.d(10): instantiated from here: assumeSorted!("a < b", RangeT!(const(Array!int)))
onlineapp.d(17): instantiated from here: test!int

Would someone explain the exact nature of this error as I fail to understand as how just telling that an Array ConstRange is assumed to be sorted actually modifies anything??

March 25

On Saturday, 25 March 2023 at 13:45:36 UTC, Olivier Prat wrote:

>

I'm trying to call assumeSorted on a const(Array) using this code snippet:

[...]

In a similar fashion, a number of methods in SortedRange do not compile if called on a const(SortedRange) or immutable(SortedRange), such as length, or front. Is this on purpose?

March 25
On 3/25/23 09:31, Olivier Prat wrote:
> On Saturday, 25 March 2023 at 13:45:36 UTC, Olivier Prat wrote:
>> I'm trying to call assumeSorted on a const(Array) using this code snippet:
>>
>> [...]
> 
> In a similar fashion, a number of methods in SortedRange do not compile if called on a const(SortedRange) or immutable(SortedRange), such as length, or front. Is this on purpose?

There are a number of interesting points in your original post but I couldn't find time to answer all of those.

I can inject this for now: :) assumeSorted returns a range object. The concept of a const range object is flawed because by nature iteration of a range happens by mutating it: For example, popBack has to do that.

So, it's normal that any range algorithm will assume a non-const object.

Ali

March 25

On 3/25/23 9:45 AM, Olivier Prat wrote:

>

Would someone explain the exact nature of this error as I fail to understand as how just telling that an Array ConstRange is assumed to be sorted actually modifies anything??

It's because a Range keeps a copy of the array (Array is a reference counted type). Since that is labeled const, then editing the Range is forbidden.

Inside SortedRange, it has this, which is causing the issue:

    static if (isForwardRange!Range)
    @property auto save()
    {
        // Avoid the constructor
        typeof(this) result = this;
        result._input = _input.save;
        return result;
    }

Overwriting the input isn't possible here, because it contains a const member.

Now, this possibly could be fixed with something like:

return typeof(this)(_input.save);

But it might just push the error to another place.

The whole thing is kind of ugly.

There is a note inside the Array Range which says it's trying to work around some old bug that is now marked as "works for me", so maybe that can be reexamined.

https://github.com/dlang/phobos/blob/17b1a11afd74f9f8a69af93d77d4548a557e1b89/std/container/array.d#L137

-Steve

March 26

On Sunday, 26 March 2023 at 02:16:15 UTC, Steven Schveighoffer wrote:

>

On 3/25/23 9:45 AM, Olivier Prat wrote:

>

[...]

It's because a Range keeps a copy of the array (Array is a reference counted type). Since that is labeled const, then editing the Range is forbidden.

Inside SortedRange, it has this, which is causing the issue:

    static if (isForwardRange!Range)
    @property auto save()
    {
        // Avoid the constructor
        typeof(this) result = this;
        result._input = _input.save;
        return result;
    }

Overwriting the input isn't possible here, because it contains a const member.

Now, this possibly could be fixed with something like:

return typeof(this)(_input.save);

But it might just push the error to another place.

The whole thing is kind of ugly.

There is a note inside the Array Range which says it's trying to work around some old bug that is now marked as "works for me", so maybe that can be reexamined.

https://github.com/dlang/phobos/blob/17b1a11afd74f9f8a69af93d77d4548a557e1b89/std/container/array.d#L137

-Steve

Thanks to both of you for the answers. It confirms my investigation and my workaround is to cast the const ranges into their non const versions, when I encounter these issues. Not very pretty.