Welcome to This Week in D! Each week, we'll summarize what's been going on in the D community and write brief advice columns to help you get the most out of the D Programming Language.
The D Programming Language is a general purpose programming language that offers modern convenience, modeling power, and native efficiency with a familiar C-style syntax.
This Week in D has an RSS feed.
This Week in D is edited by Adam D. Ruppe. Contact me with any questions, comments, or contributions.
See more at the announce forum.
This week, I wrote on Stack Overflow about auto ref returning functions, what they do and why you'd use them. Here, I'll reproduce that answer for this audience.
auto return functions' primary use case is in a template where the function body changes based on some compile time parameter. auto ref just extends that to allowing a ref return too. Behold:
auto ref foo(string magic)() { static if(magic == "use ref") { int* x = new int; return *x; } else { return 0; } } void main() { foo!""(); foo!"use ref"(); }
Each unique set of compile time arguments will generate a different function. Those different functions have entirely different code.
This is the function with an empty string:
Disassembly of section .text._D3iii15__T3fooVAyaa0_Z3fooFNaNbNiNfZi: 00000000 <_D3iii15__T3fooVAyaa0_Z3fooFNaNbNiNfZi>: 0: 31 c0 xor eax,eax 2: c3 ret 3: 90 nop 4: 90 nop 5: 90 nop 6: 90 nop 7: 90 nop
As you can see, it is most trivial - return 0. No fancy ref return there. This is the one with use ref:
Disassembly of section .text._D3iii29__T3fooVAyaa7_75736520726566Z3fooFNaNbNcNfZi: 00000000 <_D3iii29__T3fooVAyaa7_75736520726566Z3fooFNaNbNcNfZi>: 0: 55 push ebp 1: 8b ec mov ebp,esp 3: b8 00 00 00 00 mov eax,0x0 8: 50 push eax 9: e8 fc ff ff ff call a <_D3iii29__T3fooVAyaa7_75736520726566Z3fooFNaNbNcNfZi+0xa> e: 83 c4 04 add esp,0x4 11: 5d pop ebp 12: c3 ret 13: 90 nop 14: 90 nop 15: 90 nop 16: 90 nop 17: 90 nop
(the mangled name has the string in it as a hexadecimal string of the ascii (well, it is actually UTF-8, unicode works too!) bytes btw, that 75736520726566 portion - recognize 0x75 as 'u' and 0x66 as 'f'. D mangled names can get ridiculously long, but the pattern is pretty simple to read once you get to know it.)
That code calls new, so the body is more complex, but notice that eax is still holding the return value there... the pointer. Now, let's take ref out of auto ref and recompile the same thing.
The first function, of course, remains the same. The second one changed though:
Disassembly of section .text._D3iii29__T3fooVAyaa7_75736520726566Z3fooFNaNbNfZi: 00000000 <_D3iii29__T3fooVAyaa7_75736520726566Z3fooFNaNbNfZi>: 0: 55 push ebp 1: 8b ec mov ebp,esp 3: b8 00 00 00 00 mov eax,0x0 8: 50 push eax 9: e8 fc ff ff ff call a<_D3iii29__T3fooVAyaa7_75736520726566Z3fooFNaNbNfZi+0xa> e: 8b 00 mov eax,DWORD PTR [eax] 10: 83 c4 04 add esp,0x4 13: 5d pop ebp 14: c3 ret 15: 90 nop 16: 90 nop 17: 90 nop
See that mov eax,DWORD PTR [eax]? It is no longer returning the pointer (which, of course, is what ref return does under the hood), but now what is pointed by it - a normal, non-ref, value return.
So that's the difference between auto return and auto ref.
Just for completeness, let's change it to ref int and see what happens:
$ dmd iii iii.d(6): Error: constant 0 is not an lvalue iii.d(11): Error: template instance iii.foo!"" error instantiating
Now it is an error to just return 0 because that isn't a valid ref.
The practical use case is that templates may make more complex decisions as to what to do in their body, and thus their return type, based on all kinds of arguments. It might just return whatever type was passed into its arguments, it might check platform version (tho that'd be some ugly code lol), whatever. auto ref allows you to cover various cases like that without needing to write separate function signatures (and thus, function bodies) yourself.
To learn more about D and what's happening in D: