When Should I Use Out Parameters

When should I use out parameters?

Out is good when you have a TryNNN function and it's clear that the out-parameter will always be set even if the function does not succeed. This allows you rely on the fact that the local variable you declare will be set rather than having to place checks later in your code against null. (A comment below indicates that the parameter could be set to null, so you may want to verify the documentation for the function you're calling to be sure if this is the case or not.) It makes the code a little clearer and easier to read. Another case is when you need to return some data and a status on the condition of the method like:

public bool DoSomething(int arg1, out string result);

In this case the return can indicate if the function succeeded and the result is stored in the out parameter. Admittedly, this example is contrived because you can design a way where the function simply returns a string, but you get the idea.

A disadvantage is that you have to declare a local variable to use them:

string result;
if (DoSomething(5, out result))
UpdateWithResult(result);

Instead of:

UpdateWithResult(DoSomething(5));

However, that may not even be a disadvantage, it depends on the design you're going for. In the case of DateTime, both means (Parse and TryParse) are provided.

Why are 'out' parameters in .NET a bad idea?

Well, they aren't a bad idea I think. Dictionary<K, V> has a TryGetValue method which is a very good example why out parameters are sometimes a very nice thing to have.

You should not overuse this feature of course, but it's not a bad idea per definition. Especially not in C# where you have to write down the out keyword in function declaration and call which makes it obvious what's going on.

C# out parameters vs returns

A good use of out instead of return for the result is the Try pattern that you can see in certain APIs, for example Int32.TryParse(...). In this pattern, the return value is used to signal success or failure of the operation (as opposed to an exception), and the out parameter is used to return the actual result.

One of the advantages with respect to Int32.Parse is speed, since exceptions are avoided. Some benchmarks have been presented in this other question: Parsing Performance (If, TryParse, Try-Catch)

Which is better, return value or out parameter?

Return values are almost always the right choice when the method doesn't have anything else to return. (In fact, I can't think of any cases where I'd ever want a void method with an out parameter, if I had the choice. C# 7's Deconstruct methods for language-supported deconstruction acts as a very, very rare exception to this rule.)

Aside from anything else, it stops the caller from having to declare the variable separately:

int foo;
GetValue(out foo);

vs

int foo = GetValue();

Out values also prevent method chaining like this:

Console.WriteLine(GetValue().ToString("g"));

(Indeed, that's one of the problems with property setters as well, and it's why the builder pattern uses methods which return the builder, e.g. myStringBuilder.Append(xxx).Append(yyy).)

Additionally, out parameters are slightly harder to use with reflection and usually make testing harder too. (More effort is usually put into making it easy to mock return values than out parameters). Basically there's nothing I can think of that they make easier...

Return values FTW.

EDIT: In terms of what's going on...

Basically when you pass in an argument for an "out" parameter, you have to pass in a variable. (Array elements are classified as variables too.) The method you call doesn't have a "new" variable on its stack for the parameter - it uses your variable for storage. Any changes in the variable are immediately visible. Here's an example showing the difference:

using System;

class Test
{
static int value;

static void ShowValue(string description)
{
Console.WriteLine(description + value);
}

static void Main()
{
Console.WriteLine("Return value test...");
value = 5;
value = ReturnValue();
ShowValue("Value after ReturnValue(): ");

value = 5;
Console.WriteLine("Out parameter test...");
OutParameter(out value);
ShowValue("Value after OutParameter(): ");
}

static int ReturnValue()
{
ShowValue("ReturnValue (pre): ");
int tmp = 10;
ShowValue("ReturnValue (post): ");
return tmp;
}

static void OutParameter(out int tmp)
{
ShowValue("OutParameter (pre): ");
tmp = 10;
ShowValue("OutParameter (post): ");
}
}

Results:

Return value test...
ReturnValue (pre): 5
ReturnValue (post): 5
Value after ReturnValue(): 10
Out parameter test...
OutParameter (pre): 5
OutParameter (post): 10
Value after OutParameter(): 10

The difference is at the "post" step - i.e. after the local variable or parameter has been changed. In the ReturnValue test, this makes no difference to the static value variable. In the OutParameter test, the value variable is changed by the line tmp = 10;

When to use in vs ref vs out

You should use out unless you need ref.

It makes a big difference when the data needs to be marshalled e.g. to another process, which can be costly. So you want to avoid marshalling the initial value when the method doesn't make use of it.

Beyond that, it also shows the reader of the declaration or the call whether the initial value is relevant (and potentially preserved), or thrown away.

As a minor difference, an out parameter needs not be initialized.

Example for out:

string a, b;
person.GetBothNames(out a, out b);

where GetBothNames is a method to retrieve two values atomically, the method won't change behavior whatever a and b are. If the call goes to a server in Hawaii, copying the initial values from here to Hawaii is a waste of bandwidth. A similar snippet using ref:

string a = String.Empty, b = String.Empty;
person.GetBothNames(ref a, ref b);

could confuse readers, because it looks like the initial values of a and b are relevant (though the method name would indicate they are not).

Example for ref:

string name = textbox.Text;
bool didModify = validator.SuggestValidName(ref name);

Here the initial value is relevant to the method.

Out parameters and exceptions

Pretty much, that is an aspect of what out means; firstly, note that out doesn't really exist - we only really need to consider ref (out is just ref with some "definite assignment" tweaks at the compiler). ref means "pass the address of this" - if we change the value via the address, then that shows immediately - it is, after all, updating the memory on the stack of Main. It can't abstract this (to delay the write) because the value could be, for example, some oversized struct that is using ref specifically for the purpose of avoiding copying it on the stack (an approach used extensively in XNA etc).

Clean Code - Are output parameters bad?

It's correct that output parameters should generally be avoided. When possible (and reasonable) it's better to just return the result. Using output variables gives you a process of Prepare - Call - Handle that is more complex than it has to be.

You don't always have to create a new type to use for return value. There are types in the framework that you can use as long as you don't need a specific name for the components in the return value:

public Tuple<int, int> CalculateMinMax()

This is of couse only good if the meaning of the return value is obvious. In the example above the two values would be expected to be the minimum and maximum that was calculated, in that order.

If the return value is more complex, you are better off creating a type for it. If it's that complex, then using output variables for it will not make for simple code either.

What's the difference between the 'ref' and 'out' keywords?

ref tells the compiler that the object is initialized before entering the function, while out tells the compiler that the object will be initialized inside the function.

So while ref is two-ways, out is out-only.

Difference between ref and out parameters in .NET

They're pretty much the same - the only difference is that a variable you pass as an out parameter doesn't need to be initialized but passing it as a ref parameter it has to be set to something.

int x;
Foo(out x); // OK

int y;
Foo(ref y); // Error: y should be initialized before calling the method

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.



Related Topics



Leave a reply



Submit