This Week in D August 21, 2016

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.

Statistics

In the community

Community announcements

See more at the announce forum.

Tip of the Week

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.

Learn more about D

To learn more about D and what's happening in D: