3

I've been investigating the out keyword in C# after reading the section about it in C# in Depth. I cannot seem to find an example that shows why the keyword is required over just assigning the value of a return statement. For example:

public void Function1(int input, out int output)
{
    output = input * 5;
}

public int Function2(int input)
{
    return input * 5;
}

...
int i;
int j;

Function1(5, out i);
j = Function2(5);

Both i and j now have the same value. Is it just the convenience of being able to initialize without the = sign or is there some other value derived that I'm not seeing? I've seen some similar answers mentioning that it shifts responsibility for initialization to the callee here. But all that extra instead of just assigning a return value and not having a void method signature?

Community
  • 1
  • 1
Matt Phillips
  • 11,249
  • 10
  • 46
  • 71

7 Answers7

13

Usually out is used for a method that returns something else, but you still need to get a different value from the method.

A good example is Int32.TryParse(input, out myVar) it will return true if it was successful and false otherwise. You can get the converted int via the out parameter.

int myOutVar;

if (Int32.TryParse("2", out myOutVar))
{
   //do something with the int
}else{
    //Parsing failed, show a message
}
Chris Kooken
  • 32,730
  • 15
  • 85
  • 123
  • 4
    In other words, `out` is used for returning multiple values without constructing a separate object to hold them, which is more efficient and sometimes more convenient. – Matti Virkkunen May 02 '11 at 20:38
  • It is also more readable like this. In the case of Int32.TryParse, it would make no sense to return the int to be converted because you if the conversion failed or not. It makes more sense to return true or false (more readable) that the conversion passed and if so, then get the converted int. – Xaisoft May 02 '11 at 20:41
  • See my comment on @taylonr's answer. I understand what it means now I guess I'm just in the camp that its better to handle the result with an exception... – Matt Phillips May 02 '11 at 20:54
  • Exceptions completely unwind the call stack and are not very efficient. This is a much more performant way to do it. It is good practice to avoid doing logic with try/catch blocks. – Chris Kooken May 02 '11 at 20:56
  • @Xaisoft: While some people like having TryXX methods return an 'ok' Boolean and store the result in an 'out' parameter, I'd suggest that using an 'out' parameter for the Boolean while returning the result may often be cleaner. Among other things, (1) function return types in generic interfaces support covariance, but 'out' parameters cannot; (2) it would often be nicer to say "Boolean ok; var whatever = something.TryXXX(ok); if (ok) useValue(whatever);" than "whateverType whatever; if (TryXXX(whatever)) useValue(whatever); – supercat Sep 01 '11 at 02:21
3

The out / ref keywords in C# should only be used when you need to return multiple values. Even then you should first consider using a container type (such as Tuple) to return multiple values before you revert to out / ref. Whenever you're returning a single value it should just be returned.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
3

A lot of times, using out can help by giving you a slight performance gain.

Consider the TryGetValue method on IDictionary (say myDictionary is an IDictionary<string, string>) Rather than doing this:

string value = String.Empty;
if (myDictionary.ContainsKey("foo"))
{
  value = myDictionary["foo"];
}

Both ContainsKey and the indexer need to look up the key in the dictionary, but you can avoid this double-lookup on the positive case by going:

string value;
if (!myDictionary.TryGetValue("foo", out value))
{
  value = String.Empty;
}

IMO, that's a decent reason for using out parameters.

rusty
  • 2,771
  • 1
  • 24
  • 23
2

Unfortunately we cannot do something like below in C#:

a,b = func(x,y,z);

something that we do in Python or other languages. out kind of overcomes that.

F# has overcome this with tuples I believe.

PS: Returning multiple values from a function might not be good always. Tiny types are good most of the times - http://www.martinfowler.com/bliki/DataClump.html

manojlds
  • 290,304
  • 63
  • 469
  • 417
  • After reading the initial answers this was exactly what I thought of. Its very interesting that non of the resources (including the book) put it that way. Essentially its a way to allow multiple return values without having to box them up into a transfer object? – Matt Phillips May 02 '11 at 20:43
1

For example, Int32.TryParse returns boolean if it parsed correctly and with the out parameter changes the value. If the parsed value is 0 and it returns true it means the value you sent to parse was 0. If it returns false then the parser failed.

BrunoLM
  • 97,872
  • 84
  • 296
  • 452
1

Some of it is for clarity. Take the TryParse() methods, like

Int32.TryParse("3", out myInt);

This returns a bool that indicates whether the string was able to be parsed into an int. If you just had

Int32.TryParse("3", myInt);

What happens when that's called? Is myInt assigned? Does TryParse return an int?

It's not readily apparent. But if I have an out parameter, then I know that the value is getting assigned, and that the return is something else.

taylonr
  • 10,732
  • 5
  • 37
  • 66
  • would this be an advantage over just throwing an exception though? If you are trying to parse an int and it fails because its a string shouldn't it be your responsibility to deal with it. I find that error detection and correction seems better left to a try catch block than an if/else statement. – Matt Phillips May 02 '11 at 20:45
  • @Matt that depends on whether the invalid format is an exceptionel case (in which case throwing an exception is correct) and you should then use int.Parse but in the case where you Can expect an invalid format (e.g. User input) you should use int.TryParse – Rune FS May 02 '11 at 20:59
  • @Matt like Rune says, it depends on the case. But at any rate .TryParse() isn't exactly clear in it's intentions.. it's almost like those "bool" enums you see that someone has False = 0, True = 1, Unknown = 2 – taylonr May 02 '11 at 22:12
1

Basically you do something like (my database read)

if (ReadSingle<UserRecord>(cmd, out user))
    Cache.Insert(cacheId, user, null,
        DateTime.MaxValue, TimeSpan.FromMinutes(3));

Or else you do something like:

user = ReadSingle<UserRecord>(cmd);
if(null != user)
   // Cache.Insert ...

It simplifies the code a little to use a boolean result (that a record was read from the database) and get the actual record into the variable via the out keyword.

Chuck Savage
  • 11,775
  • 6
  • 49
  • 69
  • great example. I find that its hard to come up with non-trivial examples for things that show beyond "its cool" or "its simple". Thanks – Matt Phillips May 02 '11 at 21:15
  • Your welcome. It took me a while to adapt this style of *Try* method calls, but it does make the code look a little nicer. – Chuck Savage May 02 '11 at 21:21