digitalmars.D.learn - I wrote a function that accepts input ranges, and I get compile errors
- pineapple (85/85) May 27 2016 I'm writing my own map function modeled after the one in phobos.
- Adam D. Ruppe (3/5) May 27 2016 add `import std.array;` i think to your module and it should make
I'm writing my own map function modeled after the one in phobos. (because I feel like it, that's why. good learning experience.) I've encountered one remarkable difference: The phobos function accepts arrays and mine does not. I understand why - I'm calling methods that arrays don't have - but what I don't understand is why the phobos function _does_ work. I haven't been able to find what in the phobos code accounts for iterables that aren't ranges. What am I missing? enum canMap(T) = isInputRange!(Unqual!T); auto map(alias func, Range)(Range range) if(canMap!Range){ return Mapping!(func, Range)(range); } struct Mapping(alias func, Range) if(canMap!Range){ alias URange = Unqual!Range; Range input; this(URange input){ this.input = input; } void popFront(){ this.input.popFront(); } property auto ref front(){ return func(this.input.front); } static if(isBidirectionalRange!URange){ property auto ref back(){ return func(this.input.back); } void popBack(){ this.input.popBack(); } } static if(isInfinite!URange){ enum bool empty = false; }else{ property bool empty(){ return this.input.empty; } } static if(isRandomAccessRange!URange){ static if(is(typeof(URange.opIndex) == function)){ alias Index = Parameters!(URange.opIndex)[0]; }else{ alias Index = size_t; } auto ref opIndex(Index index){ return func(this.input[index]); } } static if(is(typeof(URange.opDollar))){ alias opDollar = URange.opDollar; } static if(hasLength!URange){ property auto length(){ return this.input.length; } } static if(hasSlicing!URange){ static if(is(typeof(URange.opIndex) == function)){ alias SliceIndex = Parameters!(URange.opIndex)[0]; }else{ alias SliceIndex = size_t; } auto opSlice(SliceIndex low, SliceIndex high){ return typeof(this)(this.input[low .. high]); } } static if(isForwardRange!URange){ property auto save(){ return typeof(this)(this.input.save); } } } version(unittest) import mach.error.unit; unittest{ import std.stdio; //import std.algorithm : map; // Works with this // no property 'popFront', etc for type 'int[]' writeln( [1, 2, 3].map!((item) => (item * item)) ); } Tangentially related question - Why does phobos use isInputRange!(Unqual!T) instead of just isInputRange!T? What's the functional difference here?
May 27 2016
On Friday, 27 May 2016 at 14:54:30 UTC, pineapple wrote:I've encountered one remarkable difference: The phobos function accepts arrays and mine does not.add `import std.array;` i think to your module and it should make arrays ranges
May 27 2016
On Friday, 27 May 2016 at 14:59:25 UTC, Adam D. Ruppe wrote:On Friday, 27 May 2016 at 14:54:30 UTC, pineapple wrote:you would get a more fine-grained import with std.range (or more even more detailed std.range.primitives). If you are interested how it works under the hood - it's pretty simple & elegant: https://github.com/dlang/phobos/blob/master/std/range/primitives.d#L2038I've encountered one remarkable difference: The phobos function accepts arrays and mine does not.add `import std.array;` i think to your module and it should make arrays ranges
May 28 2016
On Saturday, 28 May 2016 at 16:25:02 UTC, Seb wrote:If you are interested how it works under the hood - it's pretty simple & elegant:I checked up on the phobos implementation and found that arrays are mutated when iterated over as ranges, which didn't rest well with me. Nor did the idea of importing some module having such a significant side-effect as whether some type can act as a range or not. So I ended up making a sort of factory that turns arbitrary objects into ranges, including arrays. Seems to work pretty well.
May 28 2016
On Saturday, 28 May 2016 at 20:43:00 UTC, pineapple wrote:On Saturday, 28 May 2016 at 16:25:02 UTC, Seb wrote:Arrays in D work differently to other languages. That's why we call them Slices ;-) See: https://dlang.org/d-array-article.html Phobos just modifies the pointer - so `a = a[1 .. $];` is nothing more than creating a new pointer.If you are interested how it works under the hood - it's pretty simple & elegant:I checked up on the phobos implementation and found that arrays are mutated when iterated over as ranges, which didn't rest well with me. Nor did the idea of importing some module having such a significant side-effect as whether some type can act as a range or not. So I ended up making a sort of factory that turns arbitrary objects into ranges, including arrays. Seems to work pretty well.are mutated when iterated over as ranges,Btw all ranges are modified during iteration, they have a state and with every popFront you change that. If you want to save the state before, you can call `.save` if it's at least a ForwardRange
May 28 2016