Issue 19981 - std.algorithm.iteration.group fails when element type has a const/immutable member
Summary: std.algorithm.iteration.group fails when element type has a const/immutable m...
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: phobos (show other issues)
Version: D2
Hardware: All All
: P3 normal
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-06-18 08:38 UTC by elpenguino+D
Modified: 2024-12-01 16:35 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description elpenguino+D 2019-06-18 08:38:29 UTC
```
unittest {
    import std.algorithm.iteration : group;
    static struct X {
        const int x;
    }
    X[] arr = [X(1),X(2),X(3)];
    group(arr);
}
```
Currently (DMD 2.086.1) this produces an unhelpful error: Error: cannot modify struct instance `this._current` of type `Tuple!(X, uint)` because it contains `const` or `immutable` members
Comment 1 Vladimir Panteleev 2019-06-18 19:51:03 UTC
It doesn't work because Group.front's return value is a ref to a field (_current), however, because the range element type has const members, it cannot be overwritten, i.e. it would break:

auto r=group(...);
auto p = &r.front.x;
auto v = *p; r.popFront;
assert(*p == v, "A const variable has changed");`.

It's not actually a problem from this side with const, but it is with immutable, which exhibits the same issue.

Not sure this is fixable in the general case, since many range algorithms have to store a copy of the range elements in some way. Adding constness to field members implies restricting some operations on them.

This could be worked around by wrapping the actual values with a proxy type which stores a pointer but forwards everything else to the pointer target (perhaps something like this exists in Phobos already):

////////////////////////////////// test.d //////////////////////////////////
import std.algorithm.iteration;
import std.stdio;
import std.typecons;

struct Ref(T)
{
    T* _obj;
    ref inout(T) getObj() inout { return *_obj; }
    alias getObj this;

    bool opEquals(ref Ref other) const { return *other._obj == *this._obj; }
}
Ref!T toRef(T)(ref T v) { return Ref!T(&v); }

void main()
{
    static struct X {
        immutable int x;
    }
    [X(1),X(2),X(2),X(3)]
        .map!((ref x) => toRef(x))
        .group()
        .writeln();
}
////////////////////////////////////////////////////////////////////////////
Comment 2 dlangBugzillaToGithub 2024-12-01 16:35:05 UTC
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/phobos/issues/10375

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB