Thread overview
Calling assumeSorted on const(std.container.Array)
Mar 25, 2023
Olivier Prat
Mar 25, 2023
Olivier Prat
Mar 25, 2023
Ali Çehreli
Mar 26, 2023
Olivier Prat
March 25, 2023

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, 2023

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, 2023
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, 2023

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, 2023

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.