The following code

import std.algorithm.iteration : filter;
import std.algorithm.mutation : move;
import std.range : iota;

static private struct S
{
    import core.memory : GC;
    @disable this(this);

    this(int x)
    {
        _ptr = cast(typeof(_ptr))GC.malloc((*_ptr).sizeof);
        *_ptr = x;
    }

    ~this() { GC.free(_ptr); }  // scoped destruction

@property auto ref value() @safe pure nothrow @nogc { return *_ptr; }
    alias value this;

    int* _ptr;
}

auto below1(size_t n,
            S s = S.init)
{
    // this could work, if the compiler could infer that
    // `s` can be implicitly converted to an r-value
    return 0.iota(n).filter!(_ => _ < s);
}

auto below2(size_t n,
            S s = S.init)
{
    // this should work, because `s` is an r-value
    return 0.iota(n).filter!(_ => _ < s.move());
}

unittest
{
    S s = S(42);
    s.value = 43;
    s.value = 42;
    assert(s.value == 42);

    // both these fail
    100.below1(s.move());
    100.below2(s.move());
}



fails to compile with DMD Git master with error message

t_scope.d(23,6): Error: variable t_scope.below.s has scoped destruction, cannot build closure

It illustrates one the simplest cases where a container-type cannot be used inside a lambda closure needed by D's great lazy ranges.

Can somebody explain why not even `below2` compiles eventhough `s.move()` is inferred to be an r-value?

Until this gets fixed in the compiler, is there something I can do in the mean-while to make it possible to use instances of `S` inside of range lambda closures?

Reply via email to