Proposal: tuple-friendly return type syntax for methods
See original GitHub issue(taken from NH discussion here: https://news.ycombinator.com/item?id=12361949)
The tuple syntax (#347), while straightforward on its own, is rather distracting in method declarations. E.g. here:
public (int sum, int count) Tally(IEnumerable<int> values)
The name of the method gets “squished” between the return type and the parameter list, even though it’s more important than either when scanning code.
I suggest adding some kind of syntax where the return type follows the parameter list to avoid this problem. There is a precedent for it in a C-style language with traditional declarators, albeit in somewhat different circumstances - C++11 has added the return-type-at-end syntax auto f(...) -> T
.
Because ->
is already used in C#, and because it is too easily confused with =>
for lambdas and expression-bodies methods, I don’t think C++11 syntax is a good fit. Instead, suggestion is to take the syntax from Ada by reusing return
:
public Tally(IEnumerable<int> values) return (int sum, int count) { ... }
or
public Tally(IEnumerable<int> values) return (int sum, int count) =>
This makes method name the first identifier on the line, inputs next, and finally outputs, matching the natural reading flow (“Tally takes values and returns their sum and count”). It’s also more consistent with Func<TArg, ..., TResult>
.
Grammar-wise, it looks like it’s a very straightforward extension on the existing constructor syntax. Basically things that would be parsed as constructors and then rejected because the identifier didn’t match the class, would now become methods. Whether to require return
, or to imply void
in its absence, is largely a matter of taste. And, obviously, return
is already a keyword, and it cannot appear in this position today, so this is fully backwards compatible.
I don’t suggest applying return
to anything other than the methods and delegates (in particular, not to properties). Tuple types are much less of an issue there from readability perspective because there’s no argument list, and thus the name of the property is always in a prominent position at the end of the line, whereas the use of return
would be confusing for properties with setters:
public (int sum, int count) Totals {
get => ...
set => ...
}
While the main motivation is for tuples, there are other circumstances where this is useful. One is any other case where the return type is complicated - for example, a gnarly nested generic:
Task<Dictionary<string, Func<bool>> Foo(object x) => ...
// becomes
Foo(object x) return Task<Dictionary<string, Func<bool>> => ...
Another is when the method itself is generic - as most C# devs know, Intellisense gets in the way when typing out something like:
public T Foo<T>()
because when you get to the first T
, it’s not declared yet, and so Intellisense suggests other identifiers in scope that happen to start with a T
; you have to explicitly close the completion list to get it out of the way, and if you forget, it’ll probably substitute something else when you press space after T
. On the other hand, with the return
syntax:
public Foo<T>() return T
Usage follows declaration for T
, and so you would get proper completion for it in Intellisense by the time you get past return
.
There’s also a marginal benefit in that this syntax permits a more natural way to apply attributes to the return value:
[return: Foo]
int Bar();
// becomes
int Bar() return [Foo] int;
Side note: this presupposes that there’s no plan to add a generic form of type-follows-name declarators to C# that would apply everywhere (akin to x: T
form used by TypeScript and many other languages). If there is such a plan, this is redundant, and return
is a poor choice, because it couldn’t be used uniformly for non-method entities with types.
Issue Analytics
- State:
- Created 7 years ago
- Reactions:12
- Comments:9 (3 by maintainers)
Top GitHub Comments
By the way, I think
->
is a good fit since it is used in C++ for the same purpose(s) and is familiar.Then it can be considered for lambda expressions to explicitly specify return type.
However, a third-person
returns
is still a good candidate because we havewhere
in the same position.Not sure if this should be permitted only for tuple types.
Closing this out. We’re doing all language design now at dotnet/csharplang. If you’re still interested in this idea let us know and we can migrate this over to a discussion in that repo. Thanks!