Bug 5351 – Add template mixin for Range Primitives using random access

Status
REOPENED
Severity
enhancement
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
Other
OS
All
Creation time
2010-12-14T09:27:14Z
Last change time
2024-12-01T16:13:43Z
Keywords
bootcamp
Assigned to
No Owner
Creator
Jesse Phillips
Moved to GitHub: phobos#9894 →

Comments

Comment #0 by Jesse.K.Phillips+D — 2010-12-14T09:27:14Z
This came form a post by Lars on how to remove the boilerplate if you already have a random access interface: To avoid the boilerplate, you could write a mixin that defines the iteration primitives for you. mixin template IterationFuncs() { int index; bool empty() { return index == length; } auto front() { return opIndex(index); } void popFront() { ++index; } // ... etc. } Then you'd just have to define opIndex() and length(), and the mixin does the rest for you. struct MyRange(T) { T opIndex(int i) { ... } @property int length() { ... } mixin IterationFuncs!(); } (I haven't tested the code above, so it probably has bugs, but you get the point.) -Lars
Comment #1 by lt.infiltrator — 2015-12-09T10:39:27Z
Are you suggesting that this boilerplate mixin should be added to phobos? It seems too inflexible for general use.
Comment #2 by Jesse.K.Phillips+D — 2016-02-11T00:29:25Z
(In reply to Infiltrator from comment #1) > Are you suggesting that this boilerplate mixin should be added to phobos? > It seems too inflexible for general use. Yes that is what's being requested http://forum.dlang.org/post/[email protected] I agree it isn't flexible, that isn't the point. It only has to do one thing well.
Comment #3 by simen.kjaras — 2017-10-30T20:16:55Z
The implementation above will fail for this simple case: MyRange!int a = [1,2,3]; a.popFront(); assert(a[0] == a.front); It could be made to work for ranges that support slicing, and assignment from the slice to the range: void popFront() { this = this[1..$]; } front and empty are then trivial calls to this[0] and length == 0, respectively. One option that only requires opIndex and length would use a wrapper struct. This solution would leave MyRange as a non-range, though - only its sliced result would be a range: struct MyRange(T) { T[] arr; T opIndex(size_t idx) { return arr[idx]; } @property size_t length() { return arr.length; } mixin rangeFuncs!(); } template rangeFuncs() { auto opSlice() { alias TT = typeof(this); struct Result { size_t _index; TT* _range; auto front() { return (*_range)[_index]; } @property bool empty() { return _index == _range.length; } void popFront() { _index++; } auto opIndex(size_t idx) { return (*_range)[_index + idx]; } } Result result; result._range = &this; return result; } } unittest { import std.range.primitives : isInputRange; import std.algorithm.comparison : equal; auto a = MyRange!int([1,2,3,4]); static assert(!isInputRange!(typeof(a))); static assert(isInputRange!(typeof(a[]))); assert(a[].equal([1,2,3,4])); } In conclusion, opIndex + length is insufficient functionality to turn something into a range.
Comment #4 by Jesse.K.Phillips+D — 2017-12-01T22:57:41Z
(In reply to Simen Kjaeraas from comment #3) > The implementation above will fail for this simple case: > > MyRange!int a = [1,2,3]; > a.popFront(); > assert(a[0] == a.front); > > It could be made to work for ranges that support slicing, and assignment > from the slice to the range: > > void popFront() { > this = this[1..$]; > } Actually this would be a good verification to add to isRandomAccessRange because your correct that this wouldn't match for random access, but such a behavior is fine for forward and bidirectional. Now that being said, the confusion of having an indexable, non-randomAccessRange with this kind of behavior would be there.
Comment #5 by simen.kjaras — 2017-12-04T09:55:27Z
isRandomAccessRange is a compile-time construct, and checking foo[0] == foo.front is generally not possible at compile-time. Even if it is, the fact they're equal right now doesn't mean they always will be (consider the fibonacci sequence 1,1,2,3,5,8,13,21..., which would have foo[0] == foo.front after one popFront, but not two). In addition, as you say, having an indexable range with semantics different from random access ranges is not at all desirable, and a recipe for disaster at some later point. I agree having this kind of functionality in Phobos would be nice, but I don't see a workable path to that goal. I'm closing this - please reopen if there are revelations that make it possible in the future.
Comment #6 by snarwin+bugzilla — 2023-03-05T19:00:20Z
Reopening this, since the proposed addition is still useful, even if (as discussed) it would require more from the "host" type than just indexing and length.
Comment #7 by robert.schadek — 2024-12-01T16:13:43Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/phobos/issues/9894 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB