2

Which one is better in terms of memory? I have always used snippet 2.. Is Snippet 1 better in anyway than snippet 2 (performance,memory) ?

Snippet 1
public void GetListOfString(ref List<string> x)
{
    x = new List<string>(){"Dave","John"};
}


Snippet 2
public List<string> GetListOfString()
{
 return new List<string>(){"Dave","John"};

}
7
  • 1
    With inlining both methods probably perform the same, memory and CPU wise. Commented Jul 16, 2015 at 4:42
  • 7
    There would no 'memory difference' as they both create a new object. Any speed difference, if any, wrt ref is also irrelevant. Use #2 and don't worry about such silliness in the sake 'performance'. The point of ref (or out) is primarily to allow the binding in the caller to be re-assigned. Commented Jul 16, 2015 at 4:43
  • 4
    @AndriyHoren -- Please note that I have assigned a new object to x ... So if ref keyword was not used , the calling function will not have the changes reflected Commented Jul 16, 2015 at 4:53
  • 3
    Snippet 2 is much better, in term of readability, The other two factors are micro-optimizations that you won't need 99.9% of the time. Commented Jul 16, 2015 at 4:57
  • 1
    In your example, it would be more appropriate to use out rather than ref because anything that is passed in is ignored anyway. It would be appropriate to use ref if you wanted to pass something in, use it in the method and potentially change it. To have a void method with a single out parameter is bad practice. Only use out parameters if you want to output multiple values that are peers or you are already returning something but want to output something else too, e.g. TryParse naturally returns a bool because it always succeeds or fails but sometimes outputs a value too. Commented Jul 16, 2015 at 5:11

2 Answers 2

4

First of all, your first example should be using out, not ref:

public void GetListOfString(out List<string> x)

The method doesn't care what the incoming value is; it just overwrites whatever was there. Using out ensures that a) the caller is not required to initialize the variable before passing it, and b) the method itself is required to initialize the variable before returning (which will ensure against bugs).


If there is any performance difference at all (and I doubt you could measure one), I would expect the first example to be slower, because it has to pass a reference to a variable. Passing by-reference means there has to be a memory location involved where the method can modify the variable's value. Returning a value is a highly optimized scenario, with the value often even stored in a register. And if the variable isn't passed by-reference, then the compiler may be able to enregister the caller's variable too, for an additional performance gain.

And of course, if data is kept in registers rather than being stored on the stack, that represents a (marginal, inconsequential, completely unimportant) reduction in memory footprint too.

But performance and memory footprint should not be your first concern anyway. The primary concern, and in 99.94% of all code the only concern, is what makes sense semantically and operationally. If the method has a need to modify a caller's variable, then pass by-reference, ref or out as appropriate to the scenario. If not, then pass by-value. Period.

Note that if just one variable of the caller needs to be modified, and the method does not otherwise have to return anything (i.e. would be void), then it is considered a much better practice to let the caller handle modifying the variable, and just return the new value for the variable (i.e. as in your second example).

If and when you come to a point in your code where for some reason, you just cannot achieve some specific and measurable performance or memory footprint goal, and you can prove that using passing by-reference will ensure that you will achieve that goal, then you can use performance as a motivation for passing by-reference. Otherwise, don't give it a second thought.

Sign up to request clarification or add additional context in comments.

Comments

1

Snippet 2 is much better in terms of readability and usability.

It is probably also slightly better in terms of performance and memory.

But this is just because the caller is forced to create a new list to even call snippet 1. You could argue that this overhead will be optimized away by the compiler, but don't rely on it.

If you had used out instead of ref for snippet 1, then I would say they are the same in terms of performance and memory.

I can sympathize with someone coming from a different programming language background thinking that snippet 1 would be better, but in C# reference types are returned by reference, not copied like they could be in some other languages.

3 Comments

"the caller is forced to create a new list to even call snippet 1" -- that is not correct. The caller is forced to initialize the variable, but null is a perfectly legal value to initialize it to (and a new is not going to be optimized away, since constructors can have side-effects).
"not copied like they could be in some other languages" -- other mainstream languages return references too. E.g. Java always does, except for primitives, and C++ does when returning pointers. The real difference in C++ is that whether the whole object or a pointer is returned depends not on the type, but on how the type is used (i.e. you decide between value and reference semantics on a per-variable and per-function basis, not on a per-type basis).
Excellent points. You are completely right. Regarding the second comment: I was indeed thinking of C++ when I wrote it - that a similar syntax in C++ could be taken to mean return by value. If I'm not mistaken I think that whether C++ actually does make a copy of the object depends on how the compiler does optimization. That is a bit interesting in itself, because it comes back around to your point about the compiler not optimizing away constructors, which it would have to do for the return value by no longer calling the copy constructor.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.