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

2016-05-28 Thread Seb via Digitalmars-d-learn

On Saturday, 28 May 2016 at 20:43:00 UTC, pineapple wrote:

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.


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.



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


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

2016-05-28 Thread pineapple via Digitalmars-d-learn

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.


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

2016-05-28 Thread Seb via Digitalmars-d-learn

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:
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


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#L2038



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

2016-05-27 Thread Adam D. Ruppe via Digitalmars-d-learn

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


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

2016-05-27 Thread pineapple via Digitalmars-d-learn
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?