Here's a few facts:

(assume R is any range type)

1. All immutable(R) cannot be iterated using popFront (obviously).

2. Most immutable(R) cannot be iterated using foreach. The exception is immutable(T[]), which can.

3. In theory, immutable(R) could be iterated if it had immutable opIndex and length. However, to return a subrange you also need immutable opSlice. foreach does not use this.

4. When passed into a function, top-level immutable is removed for arrays and pointers, but no other type (can someone tell me why?).


Now, suppose I want to write a simple function that looks for a subrange in a range of ranges. Here's what I would probably write (ignoring custom predicates, optimisations etc.)

RoR findSubrange(RoR, R)(RoR ror, R r)
    if (isInputRange!RoR &&
        isInputRange!(ElementType!RoR) &&
        isInputRange!R)
{
        for (; !ror.empty; ror.popFront())
                if (equal(ror.front, r))
                        break;
        return ror;
}

This function has a few problems:

A. If you pass an immutable array for ror, the top-level immutable will be stripped, giving you a mutable ror. Great. However, only the top level immutable is stripped. If the subranges are immutable then they will stay immutable and the second line of the template constraint will fail.

B. If you change the second line to isInputRange!(Unqual!(ElementType!RoR)) then you will correctly accept immutable arrays, but you also end up accepting ranges of other immutable ranges, which in general are not iterable, so the call to equal will fail.

C. If you change the second line to isIterable!(ElementType!RoR) then it will fail when the element type has opApply. Also, equal only requires isInputRange, so whether or not it fails depends on whether equal uses popFront or not (it doesn't for arrays, but it could...)

D. If RoR is any sort of wrapper around arrays (e.g. map!"a"(ror)) then it will fail because top level immutable is not stripped. In theory, you could iterate the map over array by using opIndex, length, and return a slice, but that would require a lot of duplication of code.


My questions are:

1. First, why is top-level immutable stripped for arrays and pointers but not other types? 2. How should you handle the special case of ranges of immutable arrays in a consistent manner? 3. How should you handle the alternate iteration method with opIndex/length/opSlice?

Cheers,
Peter

Reply via email to