The last changes to range

Andrei Alexandrescu SeeWebsiteForEmail at
Sat May 29 14:30:43 PDT 2010

On 05/29/2010 03:05 PM, Philippe Sigaud wrote:
> On Sat, May 29, 2010 at 18:45, Andrei Alexandrescu
> <SeeWebsiteForEmail at <mailto:SeeWebsiteForEmail at>>
> wrote:
>     I plan to make two more (hopefully the last two) changes to the
>     range abstraction this morning.
> Does that mean that you changed some other parts recently?

Not recently, I think I made the last changes before you joined the gang.

>     1. First, I want to define this:
>     // inside range type SomeRange
>     @property SomeRange save();
> vote++
> That should make it clear you need a forward range for an algorithm.


>     The idea is that save() provides a guaranteed means to take a
>     snapshot in a range's state. The notable absents are input ranges -
>     they are unable to define save(), and therefore some algorithms
>     won't apply to them.
> I think many ranges and algorithm that you put in std have a constraint
> on InputRange that should be changed to ForwardRange. Most (all?) of the
> lazy ones should probably ask for a ForwardRange. Don't forget to update
> that part.

I'm not sure about that. Could you give an example? Why would map() not 
work with an input range?

>     2. swapFront, swapBack, and swapAt methods
>     // inside range type SomeRange
>     void swapFront(ref ElementType!SomeRange obj);
>     void swapBack(ref ElementType!SomeRange obj);
>     void swapAt(size_t i, ref ElementType!SomeRange obj);
>     All functions are optional and are needed if and only if front(),
>     back(), and opIndex() return rvalues. The idea is to provide a cheap
>     means to move elements in and out of ranges without creating extra
>     copies. There's more detail about this of increased subtlety, please
>     ask.
> Will that be associated with a constraint template? And why methods
> instead of free functions?

They will be methods because they must be primitive operations of the 
respective ranges. However, there will be wrappers like this:

// at module scope
void swapFront(Range)(Range r1, Range r2)
     static if (is(typeof(&(r1.front)) == ElementType!(Range)*)) {
         swap(r1.front, r2.front);
     } else {
         static assert(is(typeof(&(r1.swapFront)), "Cannot swap ranges");

>     3. sameFront()
>     The gnarly bringToFront() algorithm needs the primitive:
>     // inside range type SomeRange
>     bool sameFront(SomeRange another);
>     I think it's necessary for future algorithms as well. It's an
>     optional primitive. In particular, if front() returns by reference
>     it's easy to infer that two ranges have the same front by comparing
>     the addresses of their front()s.
> And if front does not return by ref? Do you then define the fronts to be
> different or compare the values?

If front() does not return by ref, the range should define sameFront() 
as a member. If it doesn't, it won't have access to a number of algorithms.

> About returning by ref, did you try to use 'auto ref'? I think I tried
> the day the feature appeared, without success, IIRC. Many ranges in
> Phobos return by ref and won't compose with other ranges because of that.

Yah, auto ref was meant for that kind of work. But generally note that 
certain ranges actively refuse to return by ref in order to not expose 
addresses of their elements. Such ranges are fit for perfectly 
encapsulated containers.


More information about the Digitalmars-d mailing list