Search code examples
c#.netperformanceout

Multiple return variables - which has best performance (out, tuple, class)?


A method that returns multiple doubles can be realized in various ways:

Through out parameters:

class MyClass
{
    static double Add3(double x, out double xp1, out double xp2)
    {
        xp1 = x + 1.0;
        xp2 = x + 2.0;
        return x + 3.0;
    }
}

Through tuples:

class MyClass
{
    static Tuple<double, double, double> Add3(double x)
    {
        Tuple<double, double, double> ret = new Tuple<double, double, double>();
        ret.Item1 = x + 1.0;
        ret.Item2 = x + 2.0;
        ret.Item3 = x + 3.0;
        return ret;
    }

Through a class gathering the results:

class MyClass
{
    class Result
    { 
        double xp1;
        double xp2;
        double xp3;
    }

    static Result Add3(double x)
    {
        Result ret = new Result
        {
            xp1 = x + 1.0;
            xp2 = x + 2.0;
            xp3 = x + 3.0;
        }
        return ret;
    }
}

My impression from the comments to this question is that people in general consider the approach with the extra class as the best practice. However, I wonder if there is a rule of thumb about the implications on run time performance for the three variants.

Does the constructor of the Tuple or the class take any extra time as compared to the out parameters?

In particular, does the variant with the out parameter have any performance advantage in the case that only one of the resulting doubles will actually be used, such as in the following snippet?

double zPlus3 = MyClass.Add3(z, out _, out _)

Solution

  • Returning multiple values through a Tuple<T1,T2,T3> or a custom class with 3 properties, is equivalent performance-wise. Tuples are more readily available (you don't have to code them) while custom classes are more convenient to use, but both approaches involve the instantiation of a reference-type, that has to be heap-allocated and later garbage collected. If you use these types just for accessing their properties once, then you are getting no added value to compensate for the heap-allocation/garbage collection overhead. Using out parameters is superior performance-wise in this case. There is a forth solution though, that combines the advantages of all these approaches: value tuples (available in C# 7.0 and later).

    static (double, double, double) Add3(double x)
    {
        return (x + 1.0, x + 2.0, x + 3.0);
    }
    

    Usage example, demonstrating tuple deconstruction:

    (double xp1, double xp2, double xp3) = Add3(13);
    

    ...or equivalently using type inference:

    var (xp1, xp2, xp3) = Add3(13);
    

    Advantages:

    1. A ValueTuple<T1,T2,T3> is as readily available as a Tuple<T1,T2,T3>.
    2. There is language support for changing the field names of a ValueTuple<T1,T2,T3> to something more meaniningful than Item1, Item2 and Item3, making them (almost) equally convenient to a custom class.
    3. A ValueTuple<T1,T2,T3> is stored in the stack, just like the out parameters. No heap-allocation and no garbage collection is involved.