user1044057 user1044057 - 27 days ago 11
C# Question

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
ref
s. 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; }


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.

Answer

The main time that "ref" is used in the same sentance 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 alwas 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).

Comments