Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: provide a way of naming lambda method parameters #12716

Closed
dsaf opened this issue Jul 25, 2016 · 9 comments
Closed

Proposal: provide a way of naming lambda method parameters #12716

dsaf opened this issue Jul 25, 2016 · 9 comments

Comments

@dsaf
Copy link

dsaf commented Jul 25, 2016

This is directly inspired by #12654 discussion (2. Generic argument name annotations - Use with generic delegates) which doesn't have a particular outcome or team's comment unfortunately. The motivation is pretty much same, though I suggest a purely language syntax implementation rather than having to use annotations directly as originally suggested.

At the moment there is no easy way to understand the meaning of expected lambda method parameters at a glance - particularly if there is more than one. For example:

public static TSource Aggregate<TSource>(
this IEnumerable<TSource> source,
Func<TSource, TSource, TSource> func) //<-- here.
{
}

Both interfaces and delegates allow to add this crucial bit of information via named parameters. However this possibility is missing when using a very general delegate such as Func<> for it's obvious flexibility benefits:

public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);

Syntax could be:

public static TSource Aggregate<TSource>(
this IEnumerable<TSource> source,
Func<TSource, TSource, TSource>(currentAggregated, element) getNewAggregated) //<-- here.
{
}

The IDE would then be able to provide this information via tooltips and other assistance. Even looking at such signature in plain text documentation would help.

Currently the MSDN documentation tries to compensate:

...Each time func is called, Aggregate passes both the element from the sequence and an aggregated value (as the first argument to func)...

(using a name like "func" is also not very helpful, it should really name the return value)

One could argue that when there are few lambda parameters then developer will be able to infer the meaning based on context and generic type argument names. If there is a lot of lambda parameters then it's a misuse of lambdas and should be refactored to reduce the number. It's a valid point, but I think the cognitive load is still there even if it's not that big.

@svick
Copy link
Contributor

svick commented Jul 25, 2016

What about a syntax like:

public static TSource Aggregate<TSource>(
this IEnumerable<TSource> source,
[ParameterNames("currentAggregated", "element")] Func<TSource, TSource, TSource> getNewAggregated) //<-- here.
{
}

This way, no new syntax is needed, only change would be in the IDE to understand this.

It's also more awkward and verbose than the original proposal, but that still sounds like a good trade-off to me.

@dsaf
Copy link
Author

dsaf commented Jul 26, 2016

It's possible to implement any language feature using half-measures. E.g. Code Contracts and Tuple<,> {Item1, Item2}. I personally prefer proper language syntax.

@dsaf
Copy link
Author

dsaf commented Jul 26, 2016

Somewhat related to #2930.

@svick
Copy link
Contributor

svick commented Jul 26, 2016

@dsaf To me, a "proper language syntax" should have one list of parameter names and types, not two separate lists. E.g. something like Func<TSource currentAggregated, TSource element, TSource> or (TSource currentAggregated, TSource element) -> TSource.

Neither of the two syntaxes I just invented feel like a good idea to me, they're more just to explain what I mean.

@dsaf
Copy link
Author

dsaf commented Jul 26, 2016

@svick I understand what you mean.

@ghost
Copy link

ghost commented Jul 27, 2016

I would prefer something with the parameter names optional but respecting declaration order, like...

Func<TPar1 par1, TPar2, TPar3, TReturn> Operation = (par2, par3) => Operate(par1, par2, par3); 

And when all parameters are named with their types, then simply infer them in the lambda...

Func<TPar1 par1, TPar2 par2, TReturn> Operation = => Operate(par1, par2);

@qrli
Copy link

qrli commented Jul 27, 2016

Why not simply define a delegate type and use it instead of Func<>? Given that Func<> is just a convenience for user defined delegate types.

@ghost
Copy link

ghost commented Jul 27, 2016

Because a delegate would require a separate boilerplate definition (no syntactic sugar). Plus, the idea is to improve lambdas for readability and tooling support.

@CyrusNajmabadi
Copy link
Member

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!

@CyrusNajmabadi CyrusNajmabadi closed this as not planned Won't fix, can't repro, duplicate, stale Nov 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants