Bug 11820 – std.algorithm functions do not function properly with `alias this`

Status
RESOLVED
Resolution
INVALID
Severity
regression
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-12-25T23:20:00Z
Last change time
2014-01-02T05:26:12Z
Assigned to
nobody
Creator
msoucy

Attachments

IDFilenameSummaryContent-TypeSize
1306ceec8f9a.dSample file from dpasteapplication/octet-stream199

Comments

Comment #0 by msoucy — 2013-12-25T23:20:22Z
Created attachment 1306 Sample file from dpaste In situations such as the attached, std.algorithm.remove produces a compile-time error when used on an object that fulfills its requirements only because of `alias this`. Issue was traced to this commit: https://github.com/D-Programming-Language/phobos/pull/1162/files
Comment #1 by msoucy — 2013-12-27T11:30:49Z
It seems that this affects more than just std.algorithm.remove - reverse also causes compile errors, possibly others.
Comment #2 by monarchdodra — 2014-01-02T05:26:12Z
> In situations such as the attached, std.algorithm.remove produces a compile-time error when used on an object that fulfills its requirements only because of `alias this`. Technically, "remove" does not produce a compile time error, because the object does *not* fulfill the requirements, and the compiler finds no adequate match. remove (and reverse) require input to be at *least* a forward range. Foo is *not* a forward range because the type returned by `foo.save` is not `Foo`, it's an int[]. This violates the requirement that you can do this with a forward range: Foo f; f = f.save; //Fails -------- The two workarounds are: 1) Pass an explicit f.bar 2) Improve Foo to be an actual forward range: give it its own "save" primitive, as well as the slicing primitives (for hasSlicing). Also, don't forget to *re*-assign the result of "remove" after calling it, or you'll just observe "shuffled" elements. //---- import std.stdio; import std.algorithm; import std.range; struct Foo { int[] bar; alias bar this; inout(Foo) save() @property inout { return this; } inout(Foo) opSlice(size_t i, size_t j) @property inout { return inout(Foo)(bar[i .. j]); } } void main() { Foo f; static assert(isRandomAccessRange!Foo); static assert(hasSlicing!Foo); f = [1,3,5,7,9]; (f = remove(f, 0)).writeln(); (f.bar = remove(f.bar, 0)).writeln(); (f = remove(f, 0)).writeln(); (f.bar = remove(f.bar, 0)).writeln(); } //----