An anachronism of the procedural world, out parameters have no place in object-oriented or functional APIs. Here are three ways to rid yourself of them.
The Example
I have created a simple program that calls a method that divides a number and returns the quotient and the remainder.
static void Main(string[] args)
{
int quotient;
int remainder;
Div(16, 3, out quotient, out remainder);
Console.WriteLine("quotient: {0}", quotient);
Console.WriteLine("remainder: {0}", remainder);
}
static void Div(int dividend, int divisor, out int quotient, out int remainder)
{
Contract.Requires(divisor != 0);
quotient = dividend / divisor;
remainder = dividend % divisor;
}
The output from this program is:
quotient: 5
remainder: 1
The method needs to return two separate values, hence the use of two out parameters. This makes perfect sense from a procedural coding style.
The Object Oriented Way
Object oriented methodology dictates that values should be represented by objects. These two integers can be represented by one value, a DivResult, which uses a small amount of memory. Therefore, I will create a DivResult struct.
public struct DivResult
{
int quotient;
int remainder;
public int Quotient
{
get
{
return quotient;
}
set
{
quotient = value;
}
}
public int Remainder
{
get
{
return remainder;
}
set
{
remainder = value;
}
}
public DivResult(int quotient, int remainder)
{
this.quotient = quotient;
this.remainder = remainder;
}
}
Now the program is object-oriented.
static void Main(string[] args)
{
var result = Div(16, 3);
Console.WriteLine("quotient: {0}", result.Quotient);
Console.WriteLine("remainder: {0}", result.Remainder);
}
static DivResult Div(int dividend, int divisor)
{
Contract.Requires(divisor != 0);
var quotient = dividend / divisor;
var remainder = dividend % divisor;
return new DivResult(quotient, remainder);
}
Something I find interesting about this approach is that you could write a custom iterator that returns dividend and divisor pairs for the DivResult.
Tuples
The .NET Framework 4 introduces the Tuple type, which is an ordered list of elements. We need to return two integers, and this is known as a pair of ints… or in tuple terms, a Tuple<int, int>. Here’s how to do that.
static void Main(string[] args)
{
var result = Div(16, 3);
Console.WriteLine("quotient: {0}", result.Item1);
Console.WriteLine("remainder: {0}", result.Item2);
}
static Tuple<int, int> Div(int dividend, int divisor)
{
Contract.Requires(divisor != 0);
var quotient = dividend / divisor;
var remainder = dividend % divisor;
return Tuple.Create(quotient, remainder);
}
Creating a tuple is as simple as calling Tuple.Create with necessary parameters. Tuples are great for returning multiple types within the context of a method or a small program. The downside in C# is the loss of context. Notice that in order to access the values, we have to use Item1 and Item2 rather than Quotient and Remainder.
Dynamic
The dynamic keyword is a new feature in C# 4 that gives us late binding. In the context of CLR types, it allows us to do something we couldn’t do in C# 3 without resorting to reflection: return anonymous types from a method.
static void Main(string[] args)
{
dynamic result = Div(8, 3);
Console.WriteLine("quotient: {0}", result.Quotient);
Console.WriteLine("remainder: {0}", result.Remainder);
}
static dynamic Div(int dividend, int divisor)
{
Contract.Requires(divisor != 0);
var quotient = dividend / divisor;
var remainder = dividend % divisor;
return new { Quotient = quotient, Remainder = remainder };
}
This has the benefit of allowing us to access the properties by their name but without type safety.
Update: A commenter (Ram) posted another way of doing this. Down the Functional Rabbit Hole explores this, and in my opinion is the best solution.
Conclusion
There is no reason to use out parameters in your own frameworks. C# is still primarily an object-oriented language, and when faced with a need to return more than one result a class or struct should be created. I presented two other ways of achieving the elimination of out parameters because it may not be desirable to create extra classes when there is no opportunity for reuse.
You will need to use out parameters when interfacing with third party libraries. This is unavoidable, but the impact can be minimized by creating a proper, object oriented wrapper around the third party library.