digitalmars.D.learn - Overload resolution (value vs reference)
- m0rph (33/33) Oct 21 2012 How does compiler selects the proper function among overloaded
- Jonathan M Davis (29/74) Oct 21 2012 http://dlang.org/function.html#function-overloading
- m0rph (1/1) Oct 22 2012 Thanks for explanation!
- Era Scarecrow (7/16) Oct 22 2012 There any word on if this was going to change? I'm meaning
- Jonathan M Davis (9/28) Oct 22 2012 AFAIK, there are no plans to change it. I don't think that it's even bee...
- Era Scarecrow (22/30) Oct 22 2012 I thought I suggested it back for a different order of
How does compiler selects the proper function among overloaded functions which differ only in the way the argument is passed (by reference or by value)? Is there a way, to control this behavior? Result of execution of the test code: passed by value: 8 passed by value: 3 passed by value: Foo(10) Test code: import std.stdio; struct Foo { int value; } void f(T)(T foo) { writeln("passed by value: ", foo); } void f(T)(const ref T foo) { writeln("passed by reference: ", foo); } void main() { // 8 is a r-vlaue, so it's passed by value f(8); // i is a l-value, it's passed by value and it's ok int i = 3; f(i); // foo is a l-value, it's passed by value again, but if structure will be big enough it'll be ineffective auto foo = Foo(); foo.value = 10; f(foo); }
Oct 21 2012
On Sun, 2012-10-21 at 19:01 +0200, m0rph wrote:How does compiler selects the proper function among overloaded functions which differ only in the way the argument is passed (by reference or by value)? Is there a way, to control this behavior? Result of execution of the test code: passed by value: 8 passed by value: 3 passed by value: Foo(10) Test code: import std.stdio; struct Foo { int value; } void f(T)(T foo) { writeln("passed by value: ", foo); } void f(T)(const ref T foo) { writeln("passed by reference: ", foo); } void main() { // 8 is a r-vlaue, so it's passed by value f(8); // i is a l-value, it's passed by value and it's ok int i = 3; f(i); // foo is a l-value, it's passed by value again, but if structure will be big enough it'll be ineffective auto foo = Foo(); foo.value = 10; f(foo); }http://dlang.org/function.html#function-overloading The big thing to remember here is that constness matters more than refness when overloads are chosen, so if you want refness to matter when choosing an overload, then the constness of the overloads must match, and if there's ever a question between const and non-const, it's the constness of the argument being passed in which wins (e.g. if you have ref T and const ref T, then which one gets called depends on whether the argument is const or not). As your code stands, if it were void f(T)(T foo) { f(foo); } void f(T)(const ref T foo) { //... } you would get an infinite loop when passing an rvalue to f, whereas void f(T)(const T foo) { f(foo); } void f(T)(const ref T foo) { //... } would not. - Jonathan M Davis
Oct 21 2012
On Sunday, 21 October 2012 at 22:47:00 UTC, Jonathan M Davis wrote:http://dlang.org/function.html#function-overloading The big thing to remember here is that constness matters more than refness when overloads are chosen, so if you want refness to matter when choosing an overload, then the constness of the overloads must match, and if there's ever a question between const and non-const, it's the constness of the argument being passed in which wins (e.g. if you have ref T and const ref T, then which one gets called depends on whether the argument is const or not).There any word on if this was going to change? I'm meaning towards structs/classes with const preference vs non-const preferences. I recall a while back while trying to make copy/move functions and I had to completely duplicate the functions so it would use the right versions.
Oct 22 2012
On Monday, October 22, 2012 22:54:44 Era Scarecrow wrote:On Sunday, 21 October 2012 at 22:47:00 UTC, Jonathan M Davis wrote:AFAIK, there are no plans to change it. I don't think that it's even been suggested. For the most part though, you can just have the non-ref version call the ref version as long as there's a ref version with the same constness, so even if you have to duplicate the function, you don't have to duplicate its body. You might be stuck with some duplication between the const and non-const overloads though if you have all 4 of them. - Jonathan M Davishttp://dlang.org/function.html#function-overloading The big thing to remember here is that constness matters more than refness when overloads are chosen, so if you want refness to matter when choosing an overload, then the constness of the overloads must match, and if there's ever a question between const and non-const, it's the constness of the argument being passed in which wins (e.g. if you have ref T and const ref T, then which one gets called depends on whether the argument is const or not).There any word on if this was going to change? I'm meaning towards structs/classes with const preference vs non-const preferences. I recall a while back while trying to make copy/move functions and I had to completely duplicate the functions so it would use the right versions.
Oct 22 2012
On Monday, 22 October 2012 at 21:58:04 UTC, Jonathan M Davis wrote:AFAIK, there are no plans to change it. I don't think that it's even been suggested.I thought I suggested it back for a different order of preferences. Basically boils down to accepting the const ones over the non-const whenever applicable and possible. Quite annoying that it was accepting non-const copy over const ref for the purposes I was going for.For the most part though, you can just have the non-ref version call the ref version as long as there's a ref version with the same constness, so even if you have to duplicate the function, you don't have to duplicate its body. You might be stuck with some duplication between the const and non-const overloads though if you have all 4 of them.Yeah I know... I guess best practice is to offer all const or non-const of particular function names/uses, but that doesn't always want to work. Let's see how did that go... struct S { ref S opAssign(S s); //move. TDPL pg. 257-259 ref S opAssign(const ref S s); //copy (almost postblitz) /* as of current, only the 'move' is always used unless the struct is actually const. inout isn't applicable I think. I'm promising not to change the input on the copy, and the move can't be const (if there's any addressing to transfer). I consider the reference the important distinction, yet the non-const is always called/preferred */ ref S opAssign(const S s); //duplicate(s) of above in reverse ref S opAssign(ref S s); //best match works better now }
Oct 22 2012