-
Notifications
You must be signed in to change notification settings - Fork 4k
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: Shorthand for simple expression lambdas #3561
Comments
👍 |
While my mind is not settled about wether this syntax is cool or ugly, let's think about these problems first: Nestingvar query = db.Orders
.Where(@.Items.Any(@.Weight > 20)); Overload resolution when passing Lambdasinstance.Do(@.SomeMethod(() => @.SomeProperty)); Is instance.Do(@.SomeMethod(@ => () => @.SomeProperty)); Constant values / throwing away the argument?var query = db.Orders
.Where(@.true); //? member access, no
.Where(@true); //? rather like this, though **extremely** small difference to verbatim identifier / strings
.Where(true); //? not unique enough, overload resolution problems Also is this allowed?var query = db.Orders
.Where({
return @.Items.Any(x => true);
}); |
I agree, it can get nasty quick. My personal opinion is that none of that is permitted and the sigil is effectively just expanded into To be a little more specific, the sigil would not represent an actual variable in scope. It could not be reused within the expression in any form. That would make nesting permitted and unambiguous (and a common scenario where I see this being useful), and the other situations non-issues since none of them would be legal. That's my personal opinion, though. |
Also mentioned in #3171 |
Swift calls this Shorthand Argument Names and uses the syntax |
@lawrencejohnston Sorta, I'm not looking to reproduce Swift's syntax in the least. I actually really don't care for the idea of having some kind of indexed sigil or implicit tuple for referencing the arguments. As mentioned above the only time that I think that this syntax should apply is for those very simple cases where you need an expression rooted in the argument, otherwise the sigil cannot be used. |
@HaloFour If C# ends up going a different direction that's fine, I just wanted to put Swift's similar feature out there as a source of inspiration/discussion. |
@lawrencejohnston You're right. I put this proposal up specifically to generate conversation so it's silly to quash it with my opinion. 😄 |
@Suchiman, statement-bodied lambdas should definitely not use this syntax. Nested lambdas are also a no-no (only innermost lambdas should be allowed to use
Of course, now we'll have four different ways to write a delegate... |
I would prefer |
IIRC Cω used an |
Have you thought about the case of passing |
I have not. This proposal only really addresses those delegates that accept a single parameter and return the result of a single expression. Is there a reason that the expression |
Not a bad idea. Maybe even a shorter syntax could work, where a dot with no LHS is used to access a member of the implicit parameter: var query = db.Orders
.Where(.Value > 50.0m)
.Select(.Employee)
.OrderBy(.Name); Off the top of my head I can't think of any reason that would be a problem. This would still have some limitations, each shared with the original proposal:
|
@bondsbw: There might be a problem if you want to test the value itself. |
This is neat, I like it. But could it be @0 ? So we could @1 / @2 if it is multiple parameter I would like to suggest # or $ too in addition to . And could this be possible to use in normal function? We may like to change the name of param for documentation in intellisense but want to shorthand in the code |
@Thaina short answer: no In regular Methods, this would lead to totally unreadable code, nothing is stopping you from naming your arguments p0, p1, p2 but nobody does for OBVIOUS reasons... |
@Suchiman In some case parameter name was included in public human readable intellisense so we may want to make it long and readable like public T GetByIndex(int indexOfItemInTheList) // This will be shown in intellisense
{
return list[indexOfItemInTheList];
} But then it make the code more messy like that |
Don't like the syntax but I really like the idea. Personally, I'd go with Swift version as @lawrencejohnston said, simply because it's more flexible even though I know this proposal is designed for the simple case. @Suchiman Sometimes the predicate can be simple and yet depends on two/three parameters, I see no reason to restrict it to only a single parameter, a single parameter doesn't imply simplicity. |
I noticed recently that a "discard" syntax is being added so people will be able to write this: if (TryGetValue(out var _))
{
// `_` is not a real variable and will not show up in IntelliSense
Console.WriteLine("Has a value, but we don't want to know what it was.");
} Since it looks like var query = db.Orders
.Where(_.Value > 50.0m)
.Select(_.Employee)
.OrderBy(_.Name); If there was already an existing variable |
I don't think that would be possible given that it could change the behavior of existing code where a variable named |
Correct me if I'm wrong, but isn't discard contextual, i.e. it will preserve existing behavior if something named If I am, I vote for one of these (with positional parameters, which I just saw above): db.Orders.Where(#1.Value > 50.0m); // Or #.Value > 50.0m
db.Orders.Where(&1.Value > 50.0m); // Or &.Value > 50.0m
db.Orders(@1.Value > 50.0m);
db.Orders(\1.Value > 50.0m); |
|
Actually, wouldn't positional parameters be ambiguous? For example, |
You are correct that Using |
How about combining simple sigil suggestion with the swift functionality. If the sigil is used alone that it's tightly coupled and cannot propagate but if the sigil is follow by a number then it can. |
I don't think positional parameters like $1 are a good idea in C#. They would provide a second fully-featured way of writing lambdas, while being vastly inferior to the current syntax (see nesting, overload resolution) and less readable. This is now being discussed at |
Actually the conversation directly moved to dotnet/csharplang#91. This issue should be closed in favour of that one. |
Sorry for the mistake! |
Closing since the issue was moved to csharplang. Thanks |
This has come up a few times on CodePlex as well as here but I've not seen any formal proposal for it so I thought I'd post one just to track it and get some conversation going about it.
Many of the LINQ extension methods accept a single argument and return a value, most often the result of a simple expression stemming from that argument. In those simple cases the developer is still required to assign the parameter value to a name that cannot shadow a name used in the current scope and then immediately reference that name in the body of the closure.
I propose that a short-hand version of this common pattern where the value of the argument can be accessed through a specific sigil which must be referenced in the method body. The following uses the sigil
@
and is the same as the query above:The text was updated successfully, but these errors were encountered: