The liabilities of binding rvalues to ref

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Sat May 4 22:49:42 PDT 2013


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


More information about the Digitalmars-d mailing list