I'm trying to understand the difference between const ref
and in
, specially when it comes to performance.
I know that in
is equivalent to const scope
, but what does the scope storage class means that references in the parameter cannot be escaped (e.g. assigned to a global variable).
mean? example code is welcome.
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
?
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With