On Tuesday, 19 August 2014 at 22:28:27 UTC, Peter Alexander wrote:
Consider these two functions:
auto ref foo(ref int x) {
if (condition) return x;
return 3;
}
auto ref bar(ref int x) {
return condition ? x : 3;
}
At a first glance, they appear to be equivalent, however foo is
a compile-time error "constant 3 is not an lvalue" while bar
compiles fine and returns an rvalue int.
The rule in the spec is "The lexically first ReturnStatement
determines the ref-ness of [an auto ref] function"
Why is this? I think it would be more consistent and convenient
to be: "An auto ref function returns by ref if all return paths
return an lvalue, else it returns by value".
Am I missing something? I don't see why foo should be rejected
at compile time when it can happily return by value.
It is especially problematic in generic code where you
opportunistically want to return by ref when possible, e.g.:
auto ref f(alias g, alias h)()
{
if (condition)
return g();
return h();
}
If g returns by ref while h returns by value then this fails to
instantiate. It would be nice if it just returned by value (as
return condition ? g() : h() would)
If I agree, you must understand that this increase wildly the
cost of the analysis required to infer return type and/or refness.
It makes the compiler implementation *way* more complex and could
increase the compilation cost a lot.
Consider that auto ref functions can happily call each others and
you'll have to go through each of them as a graph, having set of
possible return type and refness, aggregate these infos on a per
function basis, removing cycles (so a function return type do not
depend on itself).
This hack in the spec come handy, and, unless we can come up with
a good implementation of a more general spec, I'd argue for it to
stay there.