On 2009-12-17 23:57:09 -0500, Andrei Alexandrescu <[email protected]> said:

There is a wart in D I'd like to eliminate. Unfortunately, that would also eliminate some valid uses.

The problem is as follows. "ref" values in function parameter lists are always bound to lvalues - never rvalues. This is, except for _one_ case:
"this" in member functions.

struct A {
    void fun() {
       ...
    }
}

A gun() { return A(); }

unittest {
    gun().fun(); // works
}

This doesn't sound so bad until the following happens:

struct A {
    ref A opAssign(ref A rhs) { ... }
}

struct B {
    @property A a() { ... }
}

unittest {
    B b;
    b.a = A.init;
}

Everything looks kosher, but the problem is b.a returns a temporary, and then that temporary is assigned to. The assignment is inoperant.

Inoperant? Not necessarily. Assigning to temporaries like that is used sometime in C++ when a temporary "proxy" object is returned, the temporary object just forwarding the assignment to the right place. Calling any function on a temporary could have "side effects", and those "side effects" might effectively be the main desired effect.

Which makes me think that the same applies to rvalues being bound to ref: they could be temporary proxies too, or other types with side effects.


For this and other related reasons I'd like to disallow binding temporaries to "this". There are cases in which you'd want to, and you'd have to insert explicit variables. But I think eliminating the binding is the right thing to do.

I agree with you that the dissimilarity for this and other arguments is not desirable.

Personally, I would allow rvalues to convert to non-const ref. There are as many valid uses for temporaries passed as arguments (like the proxy object) than there are for temporaries passed as "this".

If you really want to disallow ref temporaries, then I'd suggest having some kind of flag allowing us to opt-in specific types. Only those types would be allowed as non-const ref temporaries. But it seem to me that we already have enough flags to deal with in D.

Which makes me think of another problem with forcing const: unlike C++, our const is transitive. This means that if your temporary is just some kind of smart pointer to somewhere, forcing it to be const would prevent any modification of the data it points to. Simple synthetic example:

        RefCountedPtr!MyObject getAnObject();

        void test(ref RefCountedPtr!MyObject object) {
                object.mutate(); // method that requires a mutable object
        }

        test(getAnObject);

Anything of the sort can't work if you force the argument to be const. In C++ you can make ref const with not much consequence because const is not transitive. But not in D.

I'm all for detecting unintended uses of rvalues, but I think forcing ref to be const is a mistake, both for "this" and other arguments. We need another solution.

--
Michel Fortin
[email protected]
http://michelf.com/

Reply via email to