On Monday, 21 May 2012 at 02:36:26 UTC, Mehrdad wrote:
On Monday, 21 May 2012 at 00:39:13 UTC, Chris Cain wrote:
On Monday, 21 May 2012 at 00:07:06 UTC, Mehrdad wrote:
How do you fix this without duplicating your code?

Simple. Don't use const for input/forward ranges.

I... guess that works...

If you want a better answer, you (might) can do it how you want, but it really can't be done without a bit of duplication (inout doesn't seem to work with my idea) and it depends highly on the types you're working with. Some types can do it relatively easily. Some types require some work.

(note: I've never written an opApply and I'm pretty sure yours isn't correct, so I'm doing my best to pseudocode it so it compiles correctly)

For instance, if p is a pointer to something ...
struct Foo(T)
{
    T * p = null;
    @property bool empty() const { return p == null; }
    @property auto front() inout { return p; }
    void popFront() { p--; }

    // Can't use inout here ... bug?
    auto save() const {
        // Transfer const to the contents
        return Foo!(const(T))(this.tupleof);
    }

    auto save() {
        return typeof(this)(this.tupleof);
    }

    int opApply(int delegate(size_t, inout typeof(p)) dg) inout
    {
        size_t i = 0;
        int r = 0;

for (auto me = this.save(); !r && !me.empty; me.popFront())
        {
            r = dg(i, me.front);
        }

        return r;
    }
}


But overall, doing stuff with a const or immutable input or forward range is just messy because, as I said, it's really not something that can be considered const and actually do something useful.

You might can make an argument that a Random Access Range could be const, and I'd agree. There's some useful things you can do with a const random access range. But an input range? I honestly can't think of a single use other than a really expensive pointer that you "deref" by calling front and check to see if it points to null by calling empty.

Reply via email to