7

Perhaps this is a bit naive of me, but I can't really seem to find/think of a decent use-case for "pass by reference". Changing an immutable string (as some other Q/As have mentioned) is generally avoidable and returning multiple variables is generally better handled by returning a Tuple, List, array, etc.

The example on MSDN is terrible in my opinion; I would simply be returning a value in the Square method, instead of having it declared as void.

It seems to me like it's a bit of a legacy part of C#, rather than an integral part of it. Can someone smarter than me try to explain why it's still around and/or some real-world use-cases that are actually practical (i.e. Changing an immutable string is avoidable in almost every case).

Trent
  • 1,595
  • 15
  • 37
  • What if you defined a function that has to adjust the value of not one, but two, or more (value type) variables? – Allmighty Sep 07 '15 at 07:07
  • The example is quite clear actually. It shows exactly how `ref` works and how you are intended to use it. However, I honestly can't think of a situation where one _has_ to use `ref` over something else, so I would like to see some answers aswell. – Dion V. Sep 07 '15 at 07:11
  • 4
    What if i want to update 2 variables using called function? ref may be helpful in this case by marking 2 variables as ref. – Sateesh Pagolu Sep 07 '15 at 07:11
  • 4
    possible duplicate of [Why use the 'ref' keyword when passing an object?](http://stackoverflow.com/questions/186891/why-use-the-ref-keyword-when-passing-an-object) – Sayse Sep 07 '15 at 07:14
  • Well, I'm not sure, but wouldn't updating multiple variable kind of go against "good practice"? A method should do one thing and one thing only from my understanding. Simple is good. Regardless of that, I find it rare to come across such a situation. – Trent Sep 07 '15 at 07:15
  • @Sayse Not really. I understand the difference between pass by reference and pass by value, I just don't see the need for pass by reference. – Trent Sep 07 '15 at 07:17
  • I'm sure it isn't best practice, in most cases. On the other hand, should a language only rely on features that are considered best-practice? There's always a need for features like these and C# supporting them isn't necessarily a bad thing. – Allmighty Sep 07 '15 at 07:18
  • @FizzBuzz - That duplicate isn't about the difference, the top answer for example states "This may be useful too if you want to change the value of an immutable object". Aside from this, there is quite possible some pattern that encourages this usage - possibly for performance of a specific operation – Sayse Sep 07 '15 at 07:19
  • [Also, note this question and it's answers.](http://stackoverflow.com/questions/30367078/why-to-use-ref-keyword-for-passing-string-parameter-in-function-calling) – Zohar Peled Sep 07 '15 at 07:24
  • Feels either duplicate or opinion based. No one forces you to use `ref` and it will likely stay in language forever (unless you have brilliant plan how to make existing code using `ref` to compile without it). Not exactly sure what input you are looking for SO (especially if you don't see post explaining why `ref` is useful as valid option). – Alexei Levenkov Sep 07 '15 at 07:24

4 Answers4

6

P.S.: I followed up on some of the comments by @KallDrexx and @newacct. I see now that they were right and I was wrong: my answer was somewhat misleading. The excellent article "Java is pass-by-value, dammit!" by Scott Stanchfield (Java-specific, but still mostly relevant to C#) finally convinced me so.

I'll leave the misleading bits of my answer striked through for now, but might later remove them.


Pass by reference is not just used with ref or out parameters. More importantly, all reference types are passed by reference (thus their name), although this happens transparently.

Here are three frequent use cases for pass-by-reference:

  • Prevent copying of large structs when passing them around. Imagine you have a byte[] array representing a binary large object (BLOB), possibly a few megabytes in size value of some struct type that contains lots of fields. A value of that type might potentially occupy quite a lot of memory. Now you want to pass this value to some method. Do you really want to pass it by value, i.e. create a temporary copy?

    You can avoid unnecessary copying of large structs by passing them by reference.

    (Luckily for us, arrays such as byte[] are reference types, so the array's contents are already passed by refence.)

    It is often suggested (e.g. in Microsoft's Framework Design Guidelines) that types having value-type semantics should be implemented as reference types if they exceed a certain size (32 bytes), so this use case should not be very frequent.

  • Mutability. If you want a method to be able to mutate a struct value that is passed to it, and you want the caller to observe the mutation of his version of that object, then you need pass by reference (ref). If the value is passed to the method by value, it receives a copy; mutating the copy will leave the original object unmodified.

    This point is also mentioned in the Framework Design Guideline article linked to above.

    Note the widespread recommendation against mutable value types (See e.g. "Why are mutable structs evil?"). You should rarely have to use ref or out parameters together with value types.

  • COM interop as mentioned in this answer often requires you to declare ref and out parameters.

Community
  • 1
  • 1
stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
  • Handling BLOBs makes sense. It's not something I've come across, so I didn't think of that. Thanks! – Trent Sep 07 '15 at 07:42
  • @FizzBuzz: But surely you've at one point or another passed a string to a method that is more than just a few characters in length. If that was passed by value, you'd always have to copy around the whole character buffer. Fortunately, since both `string` and `char[]` are reference types, that won't happen. But there's still pass-by-reference going on *behind the scenes*. – stakx - no longer contributing Sep 07 '15 at 07:50
  • Yeah, I think reference types is a bit of a special scenario. It's behind the scenes in C#. I'm more interested in when one would *have* to specify `ref`, such as the interop example. – Trent Sep 07 '15 at 08:05
  • 4
    Isn't this answer somewhat misleading? Passing reference types around doesn't pass by reference but passes the pointer value by reference. Thus you would still want to use the `ref` keyword if you want your callee to change what object the caller is actually referencing. – KallDrexx Sep 08 '15 at 18:18
  • @stakx: No, the term would be meaningless if it meant different things in different languages. It must be used consistently across languages for it to be meaningful. Primitives types in C# can be passed by reference (with `ref`) or by value (without `ref`). Reference types in C# can be passed by reference (with `ref`) or by value (without `ref`). Passing by value or by reference has nothing to do with the type. – newacct Sep 08 '15 at 20:38
  • 1
    @stakx: Pass-by-value/by-reference is not about what it does underneath, but about what the *code structure* looks like. You can pass a variable to a pass-by-reference parameter, and then inside the function, you can directly assign (`=`) to the parameter, and it will have the same effect as directly assigning to the passed variable in the calling scope. Regardless of type. With a pass-by-value parameter, directly assigning (`=`) to the parameter has no effect on the calling scope; regardless of type. This definition works consistently across languages. – newacct Sep 09 '15 at 09:08
  • @stakx: Yes, underneath, passing a variable to a by-reference parameter might be implemented as taking a pointer or something, and inside the function, accessing that parameter might be implemented as dereferencing that pointer or something, but that is all hidden to the programmer. Pass-by-value/by-reference is about what the code looks to the programmer. Yes, you can do the same thing as pass-by-reference using pass-by-value of pointers but you would have to explicitly take address when passing and dereference inside the function, etc., which is a different code structure. – newacct Sep 09 '15 at 09:10
  • @newacct, KallDrexx: I see now that I was dead wrong. I would be grateful if you could briefly review my edited answer and see if it is less misleading now. – stakx - no longer contributing Sep 10 '15 at 08:00
4

Suppose you want to have a function that mutates a value (Notice, value, not object), and you also want that function to return some success indicator. A good practice would be to return a boolean indicating success / failure, but what about the value? So you use a ref:

bool Mutate(ref int val)
{
  if(val > 0)
  {
     val = val * 2;
     return true;
  }
  return false;
}
Amit
  • 45,440
  • 9
  • 78
  • 110
  • Would you not use the `out` parameter in this case, along with the rest of the code using `TryX` methods? (Of course, you could use this way..) – Sayse Sep 07 '15 at 07:22
  • 1
    @Sayse - I don't see why that's better. Adding unneccesary exceptions, and generating confusing API. `ref` is obvious, it expects a valid value, `out` can accept an uninitialized variable. – Amit Sep 07 '15 at 07:25
  • Because the rest of your code is probably using it (`int.TryParse` et al.) so I'd favor consistency. I'm not disagreeing with your answer – Sayse Sep 07 '15 at 07:28
3

It's true that in C# there are usually alternatives to ref and out - for example, if you want to return more than one value to the caller, you could return a tuple, or a custom type, or receive a reference type as a parameter and change multiple values inside it.

However, these keywords can still be a convenient solution in situations like interop:

// C
int DoSomething(int input, int *output);

// C#
[DllImport(...)]
static extern int DoSomething(int input, ref int output);
Theodoros Chatzigiannakis
  • 28,773
  • 8
  • 68
  • 104
  • `ref` and `out` are not the only scenarios where things are passed by reference. Foremost, all reference types are passed by reference (that is why they are called reference types after all), no matter where they appear in a method's signature. – stakx - no longer contributing Sep 07 '15 at 07:25
  • @stakx: Reference types get *their reference passed by **value**.* That's why you can freely assign new values to your parameters without the caller noticing – because it's not an alias to the variable passed in. – Joey Sep 07 '15 at 07:27
  • @stakx: Actually, when you pass a reference type without the `ref` keyword, you are not passing it by reference, but you are passing it's reference by value. – Zohar Peled Sep 07 '15 at 07:27
  • @Joey: Yes, of course. Even a reference is a value at the lowest level, there is nothing else. But the C# language abstracts that away; we don't need to go to such a low level. (Unless you're programming in LISP, you don't usually need to consider your program's instructions as data, either, do you?) – stakx - no longer contributing Sep 07 '15 at 07:29
  • @Zohar: Ah, I see. Perhaps I misunderstood the OP's question then. (In that case, both you and Joey are correct and I withdraw my objection.) – stakx - no longer contributing Sep 07 '15 at 07:34
  • Ah! Interop! I knew I was missing something obvious. – Trent Sep 07 '15 at 07:44
0

There are indeed only few cases where explicit ref parameters are useful from a functional point of view.

One example I have seen:

public static void Swap<T>(ref T a, ref T b)
{
    var temp = a;
    a = b;
    b = temp;
}

Such a method is useful in some sort algorithms, for example.

One reason why ref parameters are sometimes used, is as an optimization technique. A large struct (value type) is sometimes passed by ref, even if the called method has no intent to modify the struct's value, to avoid copying the structs contents. You could argue that a large struct would better be a class (i.e. a reference type), but that has disadvantages when you keep large arrays of such objects around (for example in graphics processing). Being an optimization, such a technique does not improve code readability, but improves performance in some situations.

A similar question could be asked about pointers. C# has support for pointers, through the unsafe and fixed keywords. They are hardly ever needed from a functional point of view: I can't really think of a function that could not be coded without the use of pointers. But pointers are not used to make the language more expressive or the code more readable, they are used as a low level optimization technique.

In fact, passing a struct by reference really is a safe way to pass a pointer to the struct's data, a typical low level optimization technique for large structs.

Is a feature that enables low level optimizations a legacy feature? That may depend on your point of view, but you aren't the only C# user. Many of them will tell you that the availability of pointers and other low level constructs is one of the big advantages C# has over some other languages. I for one don't think that ref parameters are a legacy feature, they are an integral part of the language, useful in some scenarios.

That does not mean that you have to use ref parameters, just like you don't have to use LINQ, async/await or any other language feature. Just be happy it's there for when you do need it.

Kris Vandermotten
  • 10,111
  • 38
  • 49