endless loop with ref and non-ref parameter

Jonathan M Davis jmdavisProg at gmx.com
Thu Jan 24 17:56:48 PST 2013


On Thursday, January 24, 2013 17:13:36 Ali Çehreli wrote:
> On 01/24/2013 12:25 PM, Era Scarecrow wrote:
> >> What is also considered in function selection is the rvalue-lvalue
> >> distinction, which shouldn't affect the outcome here either.
> > 
> > In case David's explanation was too confusing, then let's look at it. If
> > your variable is non-const, it will always select a non-const matching
> > one first. If there is no matching non-const, it converts it to const,
> > then tries again.
> > 
> > void foo(A a) {
> > writeln("without ref");
> > //a is an lvalue but not const
> > //Foo(A) matches closer. Infinite loop
> 
> And that's exactly why this issue is so confusing.
> 
> Normally, const vs. immutable parameters are different in the way that
> they accept arguments:
> 
> - immutable is "limiting" because it insists that the argument is immutable.
> 
> - const is "welcoming" because it accepts mutable, const, and immutable.
> 
> However, according to your example and explanation above, in this case
> const is not welcoming but limiting! What the example shows is that,
> because the following function takes 'const ref A', now it "wants"
> 'const A' but not 'A'. See, how in this case 'const' is not welcoming?
> 
> That is the problem in this whole confusing situation.
> 
> If there is another explanation that would bring sanity to the way I see
> things, I would love to hear about it. Does my understanging above
> regarding "limiting" vs. "welcoming" off? Perhaps that's where I go wrong?

I've never heard anyone describe it that way before. const is more generic, 
whereas immutable is more specific. But from the compiler's point of view, 
passing a non-const object to a const function means doing a conversion (from 
mutable to const), whereas calling a function of the same type does not 
require a conversion. I believe that _that_ is the core of why ref takes 
precedence over const.

The overload rules avoid converting types as much as possible. So, if you have

auto foo(A a) {...} //#1
auto foo(const A a) {...} //#2

A a;
const A ca;
foo(a); //calls #1
foo(ca); //calls #2

The same goes with ref. When passing an lvalue, the ref requires no conversion 
or copy, whereas without ref, a copy is required. So,

auto foo(A a) {...} //#1 
auto foo(ref A a) {...} //#2

A a;
foo(a); //calls #2
foo(createA()); //calls #1

The question is what happens when you start mixing const and ref. You have to 
choose which has precedence. It's obvious what to do when you have all of the 
combinations

auto foo(A a) {...} //#1
auto foo(ref A) {...} #2
auto foo(const A) {...} //#3
auto foo(ref const A) {...} //#4

A a;
const A ca;
foo(a); //Calls #2
foo(ca); //Calls #4
foo(createA()); //Calls #1
foo(createConstA()); //Calls #3

The problem is what to do when you only have a subset:

auto foo(ref A) {...} #2
auto foo(const A) {...} //#3

A a;
const A ca;
foo(a); //Calls #2
foo(ca); //Calls #3
foo(createA()); //Calls #3
foo(createConstA()); //Calls #3

or

auto foo(A a) {...} //#1
auto foo(ref const A) {...} //#4

A a;
const A ca;
foo(a); //Calls #4
foo(ca); //Calls #4
foo(createA()); //Calls #1
foo(createConstA()); //Calls #1

or etc...

The compiler _has_ to pick either const or ref as having higher precedence. 
ref was almost certainly chosen as having higher precedence because it avoids 
a conversion, but also by picking ref, you end up with fewer unnecessary 
copies, making it the more efficient choice. So, from the standpoint of both 
type conversions and efficiency, it makes more sense for ref to have precedence 
over const than the other way around.

The reality of the matter is that regardless of whether const or ref had 
precedence, you'd still need all 4 overloads or you'd have problems. auto ref 
and inout can help reduce the number of overloads required, but the function 
needs to accept all of the type combinations in order to avoid having to 
convert the type or make unnecessary copies.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list