why is the return keyword not required in expression bodied methods

389 views Asked by At

Looking at expression bodied methods, I am trying to understand why the return keyword is not used.

For example with

public int GetAge() { return this.Age; }

I would have expected

public int GetAge() => return this.Age;

as opposed to the correct

public int GetAge() => this.Age;

Why is the return keyword not required/allowed in this case?

1

There are 1 answers

0
Waescher On

Expressions are short methods by convention. It's all about the delegation of a "thing" to do and what it takes to declare the contract: What you have and what you want in return.

It's pretty good to see in Lambdas: While you'll see this most of the time ...

    var tims = users.Where(u => u.Name.StartsWith("Tim"));

... it is perfectly valid to write ...

    var tims = users.Where((User u) => u.Name.StartsWith("Tim"));

... and even:

    var tims = users.Where((User u) => { return u.Name.StartsWith("Tim"); });

The latter is a full featured delegate syntax with arguments (User u) the curly braces for the method scope and the single-line body. In fact, this is quite the same method as this (except the lack of a method name):

    private bool IsTim(User u)
    {
        return u.Name.StartsWith("Tim");
    }

Which by the way would allow your lambda to look like this because IsTim() has exactly the same signature as the predicate for the Where-clause (= the lambda determining whether a user is a match or not).

    var tims = users.Where(IsTim);

Skipping the last example, all of the other three lambda predicates do exactly the same thing but look pretty different:

 1    u => u.Name.StartsWith("Tim")
 2    (User u) => u.Name.StartsWith("Tim")
 3    (User u) => { return u.Name.StartsWith("Tim"); }

Coming from case 3 to case 1 over the last years, the .NET team tried to minimize the keystrokes necessary to achieve the same thing. Delegates 3 have been there forever but with the introduction of Lambdas and Linq, Microsoft needed to simplify the delegating signature which led us to 2 and 1.

While case 2 is basically exact the same thing as case 3, case 1 is only valid in the correct context. It does not define the type of u but infers it in the context it is called. If you call this lambda on a list of users, u will be a user object. If you call it on a list of strings, it's representing a string (and won't compile in this case).

It took a while that Microsoft took over this logic to method and even property bodies but the logic is still the same: Why won't you reduce the necessary keystrokes if you can infer the arguments, return types and methods scopes by it's context?

That's why these two methods are exactly the same:

    private bool IsTim(User u)
    {
        return u.Name.StartsWith("Tim");
    }

    private bool IsTim(User u) => u.Name.StartsWith("Tim");

u.Name.StartsWith("Tim") will always return a boolean value and the runtime already knows the arrow => to split the method arguments from the method body. It really is "pointing" to the expression producing the return value.

"Pointing to a return value" explains why there should not be a return keyword in public int GetAge() => this.Age;.