chevron_left chevron_right
Login Register invert_colors photo_library


Stay updated and chat with others! - Join the Discord!


Tutorial C# - Returning multiple values filter_list
Author
Message
C# - Returning multiple values #1
Have you ever been stuck in the position where your method may need to return more than one thing, and don't know a way out?

Take for example, if you were writing a function that performed integer division:
Code:
int Divide(int numerator, int denominator)
{
    int div = 0;
    while (numerator >= denominator)
    {
        ++div;
        numerator -= denominator;
    }
    return div;
}

Code similar to this is fairly common on embedded platforms where integer division is necessary and no built in instructions can handle it. Anybody that knows anything about division using this method knows that it also computes the modulo, which is simply the numerator at the end of the while loop. What if you wanted to output the result in a format such as this:
Code:
10/7:  1 3/10
You could, of course, simply copy the division function and modify it to produce the mod:
Code:
int Mod(int numerator, int denominator)
{
    while (numerator >= denominator)
        numerator -= denominator;
    return numerator;
}
and then write your code as follows:
Code:
void ComputeAndPrint(int numerator, int denominator)
{
    int div = Divide(numerator, denominator);
    int mod = Mod(numerator, denominator);
    Console.WriteLine($"{numerator}/{denominator}: {div} {mod}/{denominator}");
}

By now, you've realized that we actually do division twice here, and you're probably wishing you can return multiple values. There are a few ways to do this. I'll outline them from worst to best.

Option 1: a struct
You can always make a divmod struct, and have the divide function simply return both numbers in it, like so
Code:
struct divmod
{
    public int div;
    public int mod;
}
divmod Divide(int numerator, int denominator)
{
    divmod result = new divmod { div = 0 };
    while (numerator >= denominator)
    {
        ++result.div;
        numerator -= denominator;
    }
    result.mod = numerator;
    return result;
}
void ComputeAndPrint(int numerator, int denominator)
{
    divmod result = Divide(numerator, denominator);
    Console.WriteLine($"{numerator}/{denominator}: {result.div} {result.mod}/{denominator}");
}
Obviously, that's messy. I hate it the most because it requires that you create a struct for every method you want to return more than one result for. So, what's an easier way?

Option 2: out variables
This one is used extensively by many, and I hate it almost as much, but the general concept is that you return one value and pass a parameter that is filled by the method itself, similar to C's use of pointer parameters. It would go something like this:
Code:
int Divide(int numerator, int denominator, out int mod)
{
    int div = 0;
    while (numerator >= denominator)
    {
        ++div;
        numerator -= denominator;
    }
    mod = numerator;
    return div;
}
void ComputeAndPrint(int numerator, int denominator)
{
    int div = Divide(numerator, denominator, out int mod);
    Console.WriteLine($"{numerator}/{denominator}: {div} {mod}/{denominator}");
}
This works of course, however you can see that over time it gets irritating, and you lose the ability to "at a glance" see how many values are coming out of the function. Additionally, you have to type the out keyword, which is more letters than I want to type. Plus, if we want to get technical, you're still only returning one value. Is there any way we can return 2 things, without using out parameters, and without creating a struct or class?

Option 3: Tuples
Thankfully, the answer is yes. C# comes built in with a data type called Tuple. It's basically an anonymous struct that you can put more than one value into. Don't be confused by the name though, you can put more than 2 values into it. Let's have a look at what the tuple implementation looks like.
Code:
Tuple<int, int> Divide(int numerator, int denominator)
{
    int div = 0;
    while (numerator >= denominator)
    {
        ++div;
        numerator -= denominator;
    }
    return new Tuple<int, int>(div, numerator);
}
void ComputeAndPrint(int numerator, int denominator)
{
    Tuple<int, int> result = Divide(numerator, denominator);
    Console.WriteLine($"{numerator}/{denominator}: {result.Item1} {result.Item2}/{denominator}");
}
This is looking better, but there is still more to be desired. It works fine for quick 2-value returns, but now we've lost any meaningful names in our return, and we have to create a new tuple, specifying with it the variable types. Sooner or later you're going to get tired of doing that, is there a way we can still use tuples and get back our named types?

Option 4: deconstructed tuples
Again, our answer is yes. In C#8, tuples can be defined, named, and created without the need to explicitly define every aspect of them or use the new keyword. This is done simply by wrapping 2 or more variables within parens. I'll go ahead and write out the basic code for that:
Code:
(int, int) Divide(int numerator, int denominator)
{
    int div = 0;
    while (numerator >= denominator)
    {
        ++div;
        numerator -= denominator;
    }
    return (div, numerator);
}
void ComputeAndPrint(int numerator, int denominator)
{
    (int, int) result = Divide(numerator, denominator);
    Console.WriteLine($"{numerator}/{denominator}: {result.Item1} {result.Item2}/{denominator}");
}
As you can see, it looks pretty much the same, except that we don't have to write Tuple anywhere. But, it can get better. We can get rid of item1 and item2 simply by giving the outputs a name, as if we were defining regular variables:
Code:
void ComputeAndPrint(int numerator, int denominator)
{
    (int div, int mod) result = Divide(numerator, denominator);
    Console.WriteLine($"{numerator}/{denominator}: {result.div} {result.mod}/{denominator}");
}
But again, it can get better. We can completely deconstruct that tuple to the point where we have just div and mod. All we need to do is delete any instance of 'result':
Code:
void ComputeAndPrint(int numerator, int denominator)
{
    (int div, int mod) = Divide(numerator, denominator);
    Console.WriteLine($"{numerator}/{denominator}: {div} {mod}/{denominator}");
}
And, it can get better (from a documentation point) even more. We can, using this form of tuple, denote exactly what each position of the tuple is simply by giving them a name in the method definition:
Code:
(int div, int mod) Divide(int numerator, int denominator)
Now, when you glance over the method, you know exactly what item1 and item2 are, and you can give them names.
Here's the final code for your reference:
Code:
(int div, int mod) Divide(int numerator, int denominator)
{
    int div = 0;
    while (numerator >= denominator)
    {
        ++div;
        numerator -= denominator;
    }
    return (div, numerator);
}
void ComputeAndPrint(int numerator, int denominator)
{
    (int div, int mod) = Divide(numerator, denominator);
    Console.WriteLine($"{numerator}/{denominator}: {div} {mod}/{denominator}");
}

Hopefully this quick tutorial helped you, let me know if you want to see more quick tips like this

[+] 1 user Likes phyrrus9's post
Reply






Users browsing this thread: 1 Guest(s)