The last changes to range

Philippe Sigaud philippe.sigaud at gmail.com
Sun May 30 03:11:27 PDT 2010


On Sat, May 29, 2010 at 23:30, Andrei Alexandrescu <
SeeWebsiteForEmail at erdani.org> wrote:

> On 05/29/2010 03:05 PM, Philippe Sigaud wrote:
>
>>
>> Does that mean that you changed some other parts recently?
>>
>
> Not recently, I think I made the last changes before you joined the gang.
>

OK, I wondered whether std.container had reverberations I wasn't aware of.
Btw, I plan to play with trees and graphs and algorithms on them. I will
modify my code to respect your container interface and see what sticks.


    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.
>>
>
> Yah.
>

Will the definition of a forward range change to incorporate save, or do you
intend to distinguish ranges that can do

    R r2 = r1;
and those that have:
    auto r2 = r1.save;
?
Until now, they were one and the same to me.



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

Because you make a copy of the input range in Map's constructor?

this(Range input) { _input = input; fillCache; }

I supposed _input = input was not possible with an input range? It's the
very definition of a forward range, no?

An eager version of map could use an InputRange as input:

template eagerMap(alias fun)
{
    typeof(unaryFun!fun(ElementType!R.init))[] eagerMap(R)(R r) if
(isInputRange!R && !isInfinite!R)
    {
        typeof(unaryFun!fun(ElementType!R.init))[] mapped;
        static if (hasLength!R)
        {
            mapped.length = r.length;
            foreach(i, elem; r) mapped[i] = unaryFun!fun(elem);
        }
        else
        {
            foreach(elem; r) mapped ~= unaryFun!fun(elem); // maybe with an
ArrayAppender?
        }
        return mapped;
    }
}



>     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);
>>
>> 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");
>        r1.swapFront(r2);
>    }
> }
>

OK. I really like this possibility to test for members and activate them
when possible. Maybe it could be abstracted away into a Select-like
template?


    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.


OK. So it's really sameFront and not equalFront or somesuch.



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

I was thinking of frustrating obstacles like:

auto m = map!"a*a"([0,1,2,3]);
auto c = cycle(m); // won't compile, m.front is not an lvalue, whereas
c.front asks for one.

Putting auto ref front() {...} in Cycle does not change anything. Too bad.


Philippe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20100530/0b1a4a1e/attachment-0001.html>


More information about the Digitalmars-d mailing list