Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std.algorithm.iteration.group fails when element type has a const/immutable member #10375

Open
dlangBugzillaToGithub opened this issue Jun 18, 2019 · 1 comment

Comments

@dlangBugzillaToGithub
Copy link

elpenguino+D reported this on 2019-06-18T08:38:29Z

Transfered from https://issues.dlang.org/show_bug.cgi?id=19981

CC List

Description

```
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
@dlangBugzillaToGithub
Copy link
Author

dlang-bugzilla (@CyberShadow) commented on 2019-06-18T19:51:03Z

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();
}
////////////////////////////////////////////////////////////////////////////

@LightBender LightBender removed the P3 label Dec 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants