Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The performance cost to using ref instead of returning same types?

Hi this is something that's really bothering me and I'm hoping someone has an answer for me. I've been reading about ref (and out) and I'm trying to figure out if I'm slowing down my code using refs. Commonly I will replace something like:

int AddToInt(int original, int add){ return original+add; }

with

void AddToInt(ref int original, int add){ original+=add; } // 1st parameter gets the result

because to my eyes this

AddToInt(ref _value, _add);

is easier to read AND code than this

_value = AddToInt(_value, _add);

I know precisely what I'm doing on the code using ref, as opposed to returning a value. However, performance is something I take seriously, and apparently dereferencing and cleanup is a lot slower when you use refs.

What I'd like to know is why every post I read says there is very few places you would typically pass a ref (I know the examples are contrived, but I hope you get the idea), when it seems to me that the ref example is smaller, cleaner and more exact.

I'd also love to know why ref really is slower than returning a value type - to me it would seem to me, if I was going to edit the function value a lot before returning it, that it would be quicker to reference the actual variable to edit it as opposed to an instance of that variable shortly before it gets cleaned from memory.

like image 227
user1044057 Avatar asked Nov 13 '11 10:11

user1044057


1 Answers

The main time that "ref" is used in the same sentence as performance is when discussing some very atypical cases, for example in XNA scenarios where the game "objects" are quite commonly represented by structs rather than classes to avoid problems with GC (which has a disproportionate impact on XNA). This becomes useful to:

  • prevent copying an oversized struct multiple times on the stack
  • prevent data loss due to mutating a struct copy (XNA structs are commonly mutable, against normal practice)
  • allow passing a struct in an an array directly, rather than ever copying it out and back in

In all other cases, "ref" is more commonly associated with an additional side-effect, not easily expressed in the return value (for example see Monitor.TryEnter).

If you don't have a scenario like the XNA/struct one, and there is no awkward side effect, then just use the return value. In addition to being more typical (which in itself has value), it could well involve passing less data (and int is smaller than a ref on x64 for example), and could require less dereferencing.

Finally, the return approach is more versatile; you don't always want to update the source. Contrast:

// want to accumulate, no ref
x = Add(x, 5);

// want to accumulate, ref
Add(ref x, 5);

// no accumulate, no ref
y = Add(x, 5);

// no accumulate, ref
y = x;
Add(ref y, x);

I think the last is the least clear (with the other "ref" one close behind it) and ref usage is even less clear in languages where it is not explicit (VB for example).

like image 72
Marc Gravell Avatar answered Oct 15 '22 19:10

Marc Gravell