Tuesday, 15 June 2021

Syntactic sugar in C# (part 1): Returning multiple values from a method in C# 7.0 (and Unity)

Here's some syntactic sugar I've discovered recently and I was quite impressed. Please note it requires C# 7.x (Unity 2019 and newer should be ok).

First, a little background:

A typical method in C# returns one value. Until recently, if you wanted to return two values, like an int and a float, you could either use out parameters, or define a helper struct. But there is other way!

Let's take a look on "old" methods first (if you want to see the new way, it' in 4-th point below).

The problem with out parameters is that returning value via them is a bit less readable than a normal return, and the problem with a helper struct is that is has to be defined. Let's see how it looks like, for reference; and then I'll show you a bit more elegant way.

Let's assume we have our method, getSomeData(), which we would like to return two values: integer age and floating point height.

The first 3 examples below are to show you some context, my "discovery" is in the 4-th point :)

1. out parameter version

The typical way, similar to references from C++: we can "return" our values by out parameters:

    private void getSomeData(out int ageout float height)
    {
        age = 100;
        height = 170.5f;
    }

    // Let's use it
    private void someMethod()
    {
        int age;
        float height;

        getSomeData(out ageout height); 

        Debug.Log(age); // 100
        Debug.Log(height); // 170.5
    }

Problem with this? Well, it doesn't quite look like returning a value. It looks like calling a method with parameters.

2. out+return version

We can return one value and get other one via out parameter:

    private int getSomeData(out float height)
    {
        int age = 100;
        height = 170.5f;
        return age;
    }

    // Let's use it
    private void someMethod()
    {
        int age;
        float height;

        age = getSomeData(out height);

        Console.WriteLine(age); // 100
        Console.WriteLine(height); // 170.5
    }

The problem with this version is that either of parameters is returned in a different way. If both are equally important, it looks strange (if not deceptive).

3. Helper struct

We can define a helper struct and return it:

    struct PersonalDetails
    {
        public int age;
        public float height;
    }

    private PersonalDetails getSomeData()
    {
        int ageToReturn = 100;
        float heightToReturn = 170.5f;

        return new PersonalDetails 
        age = ageToReturnheight = heightToReturn };
    }

    // let's use it
    private void someMethod()
    {
        var myDate = getSomeData();

        Console.WriteLine(myDate.age);
        Console.WriteLine(myDate.height);
    }

This version is very clean and readable when we define and call out method, but...


... before that it requires us to create a whole new structure, just for returning two values at once.

4. Sugar in C#7!

So it seems... We can just return two values at once!

        private (int agefloat heightgetSomeData()
        {
            int ageToReturn = 100;
            float heightToReturn = 170.5f;

            return (ageToReturnheightToReturn);
        }

        // now let's use it
        private void someMethod()
        {
            var myDate = getSomeData();

            Console.WriteLine(myDate.age);
            Console.WriteLine(myDate.height);
        }


Aaand here is our magic. In the method declaration we put (int age, float height) in the place we would normally place the returned type.

Then we can assign it to a variable, and use it - just like that! What's more, we can access the returned values after a dot, refering to them by names from the method declaration.


BTW if you wonder what type is myDate here, Console.WriteLine(myDate.GetType()), gives us:

    System.ValueTuple`2[System.Int32,System.Single]

So instead of 

    var myDate = getSomeData();

...we could write:

    (int agefloat heightmyDate = getSomeData();

Also nice and clean, isn't it?

No comments:

Post a Comment

Python crash course part 10: inheritance and polymorphism

In the last part we've shown how to create and use a class in Python. Today we're going to talk about inheritance: wchich means cre...