Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between 'const ref' and 'in'?

Tags:

d

I'm trying to understand the difference between const ref and in, specially when it comes to performance.

  1. I know that in is equivalent to const scope, but what does the scope stor­age class means that ref­er­ences in the pa­ra­me­ter can­not be es­caped (e.g. as­signed to a global vari­able). mean? example code is welcome.

  2. How do I decide between const ref and in when implementing a function? I know with ref the object doesn't get copied because it's a reference, but is the same true with in?

like image 288
Arlen Avatar asked Dec 15 '11 05:12

Arlen


2 Answers

1) the scope parameter storage class means that you're not allowed to escape a reference to the parameter. Example:

Object glob;

struct S
{
    Object o;
    void foo(scope Object o)
    {
         this.o = o; // Not allowed! 'o' must not be escaped
         glob = o; // ditto
    }
}

Note that DMD is not very good at detecting this. The above example currently compiles, but is not allowed.

scope is most useful for delegate parameters:

void foo(scope void delegate() dg)
{
    /* use dg */
}

void main()
{
    int i;
    foo({ ++i; });
}

In the above example, no closure needs to be allocated for the anonymous function even though it has an upvalue, because foo "guarantees" (it is the compiler's job...) that the delegate isn't escaped. DMD currently does implement this optimization.

2) I think the idea is that when both const and scope is used, the compiler could theoretically pass by reference or value at will, which is why the in shortcut is useful. DMD doesn't take advantage of this right now, but it's a handy shortcut nevertheless, and it has some documentation value.

In short, in won't currently gain you any performance unless it's used on a delegate. ref can gain you some performance with large structs or static arrays. When ref is used for performance reasons, const is often used to document (and enforce) that the ref is not used to update the original value.

like image 137
jA_cOp Avatar answered Nov 17 '22 18:11

jA_cOp


  1. It's not legal for scope parameters to escape the function. The compiler is supposed to guarantee that no references to that data escape the function. It's used primarily with delegates, since it allows the compiler to avoid allocating a closure, since it knows that the delegate won't escape.

  2. const ref is const - just like in would be - but the variable is passed by reference instead of being copied, so you avoid a copy. However, unlike C++ const ref does not work with rvalues. It must be given an lvalue. So, if you declare a parameter to be const ref, it's going to be limiting in what you can pass to it. You'll generally have to declare a variable to pass to it, whereas in will accept a temporary.

    void func(const ref int var) {}
    int a;
    func(a); //legal
    func(7); //illegal
    

Both of those calls would be legal if func took const or in. So, in general, the question is not whether you should use const ref or in. The question is whether you should use const or in. And in that case, the question is whether you want to use scope or not, since they're both const. And you use scope if you want to ensure that no reference to variable that you pass in will escape that function, so it's generally only used with delegates but could be useful with classes or arrays.

However, pure on a function guarantees that no references to any of its arguments can escape except via the return value (since pure functions can only use global variables if they're immutable or are value types and are const), so pure generally gives you all that you need for parameters which are classes and arrays. In addition, if the return type is a class or array, you general don't want to make it so that the arguments can't escape, because then instead of being able to reuse anything from those arguments in the return value, the function is forced to make a copy, which is generally less efficient.

So, scope is generally only of use with delegates, but upon occasion is useful with classes or arrays. It's already generally preferable for functions to be pure anyway, so that takes care of most of the issue. As such, while it doesn't hurt to use in, there's often little point in using in instead of const. And you generally only use const ref if you really want to avoid copying the variable being passed in, because otherwise you can only pass lvalues to that function. You can overload a function such that it has version which takes const and one which takes const ref, but that obviously results in code duplication, so unless you really want const ref, it's probably just best to use const.

EDIT:

scope has yet to be implemented for anything other than delegates (as of 2013-06-18), so using either scope or in with anything other than delegates is ill-advised. At the moment, they're misleading, and if/once scope is implemented for anything other than delegates, there's a high risk that your code will break due to references to the variables marked with scope or in escaping.

like image 29
Jonathan M Davis Avatar answered Nov 17 '22 18:11

Jonathan M Davis