Definition of "OutputRange" insuficient

monarch_dodra monarchdodra at gmail.com
Tue Jul 17 03:44:35 PDT 2012


I was trying to fix a few bugs in algorithm, as well as be more 
correct in template type specifiers, and I have to say: There is 
a serious restraint in the definition of an outputRange.

The current definition of "isOutputRange" is simply that "an 
output range is defined functionally as a range that supports the 
operation put".

The problem with this is this definition is not very useful (at 
all). Not just because it lacks front/popFront (this is actually 
OK). It is because it lacks an "empty". This makes it virtually 
un-useable unless you are blind writing to an infinite output 
range.

The proof that it is useless is that NOT A SINGLE ALGORITHM is 
compatible with output ranges. All algorithms that really only 
require an "output" systematically actually require 
"isForwardRange", or, worse yet "isInputRange" (!). This is only 
because they all make use of range.empty.

Here is an example of me trying to write "fill" respecting output 
range restrictions.

----
void fill(Range1, Range2)(Range1 range, Range2 filler)
     if (isOutputRange!(Range1, ElementType!Range2) && 
isForwardRange!Range2)
{
     enforce(!filler.empty);
     auto t = filler.save;
     while (!range.empty) //Crud...
     {
         if (t.empty) t = filler.save;
         put(range, t.front);
         t.popFront();
     }
}
----
Almost... but no cookie.

If the argument against this is "but the output range "can't know 
if it empty"/"may never be empty", then is why we have an 
"isInfinite" definition... isn't it?

On the same note, why is the definitions of "inputRange" so 
divergent from outputRange. Shouldn't inputRange's definition 
mirror output's and be "supports get" (and "is empty")?

Shouldn't a correct "front/popFront" _only_ be required once we 
reach "forwardRange" and it's ability to save?

Here is an example of an implementation of fill, that only 
requires the filler to be an input range, if it has infinity.
----
void fill(Range1, Range2)(Range1 range, Range2 filler)
     if (isOutputRange!(Range1, ElementType!Range2) && 
isInputRange!Range2
         && isInfinite!Range2)
{
     while( !range.empty )
     {
         put(range, get(filler));
     }
}
----

The current definition makes anything like near impossible.


More information about the Digitalmars-d mailing list