Here are the issues that need to be addressed by any solution reconciling rvalues and passing into functions. This post is not arguing for any particular solution or approach, but lays down the issues that any approach must be judged by.

1. The LRL (Lvalue-Rvalue-Lvalue) problem.

This has been long mentioned as an argument in defining C++'s references. The crux of the issue is that caller code passes an lvalue, and the callee code receives an lvalue, but in the middle there's an rvalue created by an implicit conversion. Consider:

void fix(ref double x) { if (isnan(x)) x = 0; }
...
float a;
...
fix(a);

If rvalues bind indiscriminately to ref, then the call is legal because of the implicit conversion float->double.

A possible solution is to disallow binding if the initial value bound is an lvalue.

2. Code evolution.

Jonathan mentioned this too. The problem here is that as code evolves, meaningful code doing real work becomes silently useless code that patently does nothing. Consider:

class Collection(T) {
  ref T opIndex(size_t i) { ... }
  ...
}

void fix(ref double x) { if (isnan(x)) x = 0; }

void fixAll(Collection!double c) {
  foreach (i; 0 .. c.length) {
    fix(c[i]);
  }
}

As design evolves, Collection's opIndex may change to return a T instead of ref T (e.g. certain implementations of sparse vectors). When that happens, the caller code will continue to compile and run. However, it won't do anything interesting: fix will be always called against a temporary plucked from the collection.

Changing return types from ref T to T or back and expecting no ill effects (aside from fixing compile-time errors) is a frequent operation in C++ projects I'm involved in. Doing worse than that would be arguably a language design regression.

Note that in function call chains fun(gun(hun())), which are common (written as fun.gun.hun etc) in the increasingly popular pipeline-style of defining processing, one function changing return style poisons the well for everybody down the pipeline. That may lead to pipelines that have only partial effect.

=======

There may be other important patterns to address at the core, please chime in. I consider (1) above easy to tackle, which leaves us with at least (2). My opinion is that any proposal for binding rvalues to ref must offer a compelling story about these patterns.


Andrei

Reply via email to