I just discovered the following interesting fact about the current state of DMD:

/// Sample struct that keeps track of the number of copy constructions (postblits) that is made in a `C`-instance.
struct C
{
    ...
    this(this) // postblit
    {
        ++copyCount; // yet another reference
    }

    struct RCStore
    {
    }

    uint copyCount = 0;          ///< copy counter
}

/// Empty
void f(T)(T a)
{
    assert(a.copyCount == 1);
}

/// Top function.
void top(T)(T a) // TODO infer that `a` is passed as an r-value?
{
    assert(a.copyCount == 0);
sub(a); // so we can do move construction here aswell?
}

/// Sub function.
void sub(T)(T a)
{
    assert(a.copyCount == 1);   // this is not neccessary
}

unittest
{
    import std.stdio : writeln;

    C x;
    f(x);
    assert(x.copyCount == 0);
    const y = x;
    assert(y.copyCount == 1);

    top(C());
}

namely that D will infer move semantics of `top`'s parameter when passing an r-value in the call to `top()` but not transitively in `top`'s call to `sub` even though this is possible.

What stops us from extending D's introspection possibilities to also provide us with knowledge about whether `C` was called with an r-value? Thereby making it possible to infer r-value referenceness, and in turn move semantics, of (templated) function parameters transitively.

A problem here is that the number of different template instantiations of a function will grow exponentially with the number of the function parameters that have a postblit. But then again aren't we all interested in maximum performance here and reduce the need for GC usage here in the case when the postblit does GC-allocated duplication of `C`-local allocations?

If template bloat will be a problem an alternative solution could be to add yet another trait, say, `__traits(isRValue, a)` the tells whether the parameter `a` was called using an r-value. That together with `static if` could branch transitive parameter passing semantics when needed. However, the code generation for such a template would not be affected if this trait is never used and code generation among templates not differing in call semantics could be reused.

This would make D even more competitive with Rust especially in the case when chaining lazy ranges with containers with allocating post-blits.

I realize that this is a somewhat competing approach to what is currently being worked on in DIP-1000.

I'm using DMD git master.

Destroy!

Reply via email to