I wrote a function that accepts input ranges, and I get compile errors when passing an array

pineapple via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Fri May 27 07:54:30 PDT 2016


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?



More information about the Digitalmars-d-learn mailing list