17

I despise out's and ref's as parameters on methods. IMHO, they make code less clean and provide opportunities for side-effects. But I concede that I may not understand their usefulness which might explain part of my loathing. Please, can someone explain a valid case for out's or ref's?

Nate Kohl
  • 35,264
  • 10
  • 43
  • 55
Byron Sommardahl
  • 12,743
  • 15
  • 74
  • 131
  • Are you asking the difference between the two, or what is the purpose of using either of them in general? And why is this tagged java? – Marlon Oct 15 '11 at 19:46
  • 2
    How do you think they provide opportunities for side-effects? – svick Oct 15 '11 at 19:46
  • http://stackoverflow.com/questions/635915/when-to-use-ref-and-when-it-is-not-necessary-in-c-sharp – Petar Minchev Oct 15 '11 at 19:47
  • I guess you need to get serious with C++ to understand why it exists, irregardless of its C# applications – Theofanis Pantelides Oct 15 '11 at 20:13
  • The most common example of usage I run into in .NET is [`Dictionary.TryGetValue`](http://msdn.microsoft.com/en-us/library/bb347013.aspx) ... I'd argue this case is more cleanly handled by an Option/Maybe type and decomposition/pattern-matching, but the question is about C# and Dictionary is a "common/shared/base" .NET runtime class: that is, can't forget backwards compatibility, must work nicely in overall language/CLR design, and have a need to support VB.NET and other similar languages. –  Oct 15 '11 at 20:19

4 Answers4

19

Basically if you need to return more than one value, it's an alternative to using something like Tuple<,> or a custom type to encapsulate the values. The canonical example is probably int.TryParse and related methods. They want to convey two pieces of information back:

  • The parsed value
  • Whether or not parsing succeeded.

Now these could actually have been written using a return type of int? etc in this case, but it's the same principle for other cases. (For example, Dictionary<,>.TryGetValue, where the value stored in the dictionary may legitimately be null.)

I wouldn't say I despise out and ref parameters, but I do believe they should only be used occasionally, and only when there isn't a better alternative. Most of the uses of ref I see on Stack Overflow are due to a misunderstanding of parameter passing.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @SaeedAmiri: Much the same, but you want the variable available as input as well. It's a bit like having an "in" parameter and another "out" parameter, except the caller can't separate the two :) – Jon Skeet Oct 15 '11 at 19:55
  • 1
    Sorry a question, Why .net team decided use `out` in tryparse not `ref`? – Saeed Amiri Oct 15 '11 at 20:00
  • 1
    @SaeedAmiri: Because the method doesn't need to know the existing value of the variable at all - why force the caller to pass in a value which isn't going to be used? The only benefit would be that it could be left with its current value on failure. – Jon Skeet Oct 15 '11 at 20:04
  • Ok, thanks, so ref is not good sample for this case, +1 for your help in comments – Saeed Amiri Oct 15 '11 at 20:08
  • Good explanation. I still hate outs and refs. An out param can't beat the expressiveness and clarity of a well named class. – Byron Sommardahl Oct 16 '11 at 00:36
7

out provides a way to return more than one value. ref is the same, except that you can also pass in a value.

Note that you can mutate an object even if is declared without ref (assuming it is mutable in the first place of course).

The alternative I prefer to out is to make a class to contain all the return values and return a single instance of that class.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 1
    "out" parameters certainly do provide an opportunity for side effects -- they require that the method either run forever, terminate abnormally, *or mutate a variable*. That's a side effect. – Eric Lippert Oct 15 '11 at 21:21
6

The "new" (C# 4.0) lock uses the ref (technically the lock statement is syntactic sugar for the new Monitor.Enter overload). It wouldn't be possible to do it without :-)

bool acquiredLock = false;

try
{
    Monitor.Enter(lockObject, ref acquiredLock);

    // Code that accesses resources that are protected by the lock.

}
finally
{
    if (acquiredLock)
    {
        Monitor.Exit(lockObject);
    }
}

so there is space for the ref in highly critical places.

The reason why simply returning a bool value wouldn't be enough is that an exception could occur between the return true of the Monitor.Enter and the bool acquiredLock = leaving your program with the question "was the lock tacken?" With the ref parameter this problem is solved.

xanatos
  • 109,618
  • 12
  • 197
  • 280
  • However, why not `var acquiredLock = Monitor.Enter(lockObject)`? I reject this is as being a *good need* for `ref`, although it is used. Arguably the standard `Dictionary.TryGetValue` is a better example as it has *two* values that must be returned (key found and value). –  Oct 15 '11 at 20:14
  • @pst: Read the last paragraph again. You can't *return* whether the lock was taken because there might be an exception *between* when the return value was put "on the stack" and when the return value was copied into the variable. – Eric Lippert Oct 15 '11 at 21:23
  • @EricLippert, just curious: why does the `Monitor.Enter` method use `ref` and not `out`? While I know that they are the same at the IL level, this still requires that the programmer actually initializes the boolean, which seems pointless. Is there a reason or was this as simple oversight? – Lucero May 16 '12 at 17:53
  • @Lucero Because an `out` wouldn't guarantee initialization. There could be an exception after the `try` and before the `Monitor.Enter`. What would be the value of `acquiredLock`? – xanatos May 17 '12 at 06:56
  • @Lucero I'll add that if you try to write something like '`bool b; try { MyTest(out b); } finally { if (b) { } }` you'll get `Use of unassigned local variable 'b'` – xanatos May 17 '12 at 07:00
2

They're pretty much the same - the only difference is that a variable you pass as an out parameter doesn't need to be initialised, and the method using the out parameter has to set it to something.

int x;
Foo(out x); 

int y;
Foo(ref y); 

Ref parameters are for data that might be modified, out parameters are for data that's an additional output for the function (eg int.TryParse) that are already using the return value for something.

Glory Raj
  • 17,397
  • 27
  • 100
  • 203