Proposal: special syntax for lambdas as last arguments in invocation expressions (for DSLs) #1151
Replies: 62 comments 12 replies
-
I do wish C# was more concise, often in Cake but not just in Cake. The whole necessity of passing |
Beta Was this translation helpful? Give feedback.
-
What about this proposal differentiates the very different behavior between these two statements? Why is I really don't like the idea of the meaning of |
Beta Was this translation helpful? Give feedback.
-
so here |
Beta Was this translation helpful? Give feedback.
-
@HaloFour typo, fixed |
Beta Was this translation helpful? Give feedback.
-
In Kotlin the following:
Would be something like this:
I really like the way Kotlin does things, it reduces code clutter quite a bit, thus make the code easier to read but then again it's a newer language, they probably learnt a lot from C# and other languages. Personally, I would really like to have something like this:
But I wouldn't mind following Kotlin and have |
Beta Was this translation helpful? Give feedback.
-
@orthoxerox I still think you have typo there. The following:
Should be
Isn't? |
Beta Was this translation helpful? Give feedback.
-
@eyalsk No, |
Beta Was this translation helpful? Give feedback.
-
I think this can be achieved by #91. I'm not trying to be negative here, but such implicit reference can be ambiguous with other local or global literals.
this also doesn't require any change in method signature. |
Beta Was this translation helpful? Give feedback.
-
@orthoxerox Okay, interestingly confusing. 😆 How it's going to work with say intellisense? |
Beta Was this translation helpful? Give feedback.
-
@eyalsk How does it work in method bodies? @MkazemAkhgary shorthand lambdas are just a bonus that falls out of these changes, the main goal is to be able to write "while-like" or "using-like" custom commands. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour I wouldn't have hijacked |
Beta Was this translation helpful? Give feedback.
-
@orthoxerox What's going to happen in this case? I mean, how do you access a member of the class with the same name within the body of the lambda? or you expect that in this case people will use the traditional syntax?
|
Beta Was this translation helpful? Give feedback.
-
@eyalsk yes, I would expect people to use the traditional syntax. |
Beta Was this translation helpful? Give feedback.
-
@orthoxerox Okay. In general, I think the idea is good and i really like to get rid of the "ceremony" of lambdas and even more in generics and other places in C# but I do find the case where all members are "exported" and implicitly available in the body confusing, I don't know, maybe it's just a matter of getting used to.. but it may also be the case of taking a good idea a bit too far. |
Beta Was this translation helpful? Give feedback.
-
@eyalsk the proposal is less about shorthand lambdas and more about providing a way to write constructs like Foo("foo") {
Bar();
Baz();
Quux();
} where Bar, Baz and Quux are available and visible only inside that Foo block. Shorthand lambdas are just a side effect of adding features to the language to support the other use case. |
Beta Was this translation helpful? Give feedback.
-
@gafter How did your implementation deal with |
Beta Was this translation helpful? Give feedback.
-
Exception-handling (throwing and catching exceptions) is exceptionally efficient in the Java runtime. Creating exceptions not so efficient because it captures a stack trace. My implementation allocates an exception object lazily, when needed, without capturing a stack trace, and throws it, catching it in the enclosing construct where the This can even be made to work in concurrent control constructs, where the exception needs to be shuttled from one thread to another. See http://gafter.blogspot.com/2006/10/concurrent-loops-using-java-closures.html . I believe the prototype contains an implementation of this concurrent loop construct. |
Beta Was this translation helpful? Give feedback.
-
In case that did not answer your question, a |
Beta Was this translation helpful? Give feedback.
-
@gafter Thanks, your answer was very clear. So basically the code would be lowered to something like this, wouldn't it? foo(bar) {
return 1;
break;
continue;
} try {
foo(bar, () => {
throw ControlFlowExceptionCache.Return(1);
throw ControlFlowExceptionCache.Break();
throw ControlFlowExceptionCache.Continue();
});
}
catch (ReturnException<int> ex) {
return ex.ReturnValue;
}
catch (BreakException ex) {
break;
}
catch (ContinueException ex) {
continue;
} Do you happen to know why JetBrains didn't do that in Kotlin? |
Beta Was this translation helpful? Give feedback.
-
Something like this http://gafter.blogspot.com/2006/09/control-abstraction.html |
Beta Was this translation helpful? Give feedback.
-
@gafter Yes, but with the option to change the default receiver inside the block, so you can say
|
Beta Was this translation helpful? Give feedback.
-
Any updates on this? Looks very neat. |
Beta Was this translation helpful? Give feedback.
-
That would be very good for MAUI One of the premises is to have declarative UI that end up needing some kind of DSL This proposal could help a lot |
Beta Was this translation helpful? Give feedback.
-
This is a mythical man-month issue. You can't just throw more teams at it hoping it will go faster :-/ |
Beta Was this translation helpful? Give feedback.
-
There are no updates on this. This would need to be championed by someone to move anywhere. |
Beta Was this translation helpful? Give feedback.
-
Is this on the consideration list for C# 11? The RemObjects C# compiler supports this Trailing Closures feature quite nicely, and Swift and Kotlin have supported this from the get-go (5+ years now). Would be great to see C# catch up to this modern must-have that can unlock all sorts of DSL-style APIs. |
Beta Was this translation helpful? Give feedback.
-
Here are a handful of examples sweeping through our codebase to kick things off: Frameworks ImprovedLINQExample: All
⇨ ⇨ ⇨
Task APIExample: Continuations
⇨ ⇨ ⇨
EF CoreExamples:
⇨ ⇨ ⇨
⇨ ⇨ ⇨
AutoMapper (not MS, but super popular/useful and would greatly benefit)Examples:
⇨ ⇨ ⇨
⇨ ⇨ ⇨
|
Beta Was this translation helpful? Give feedback.
-
Is this proposal abandoned? Kotlin's lamdba syntax is so elegant and neat, it would be awesome to see it in c# |
Beta Was this translation helpful? Give feedback.
-
Please. Do this. Already. Biggest missing feature in C# by a long-shot. |
Beta Was this translation helpful? Give feedback.
-
I love this feature (I use it mostly in Kotlin but Swift and Scala have it too, amongst others) and I think C# would benefit greatly from its introduction. Even better would be if somehow object initialiser expressions could be retconned into being trailing lambdas (inlined, of course) so that normal C# would be supported inside the expression: var p = new Point
{
X = 4;
if (someBool)
{
Y = 5;
}
} This is a bit of a pain point around |
Beta Was this translation helpful? Give feedback.
-
Warning: lots of Kotlin-inspired sugar.
Rationale: C# as it is doesn't support DSLs that well. Several features in Ruby, Groovy and Kotlin allow developers to author code that looks like native constructs.
Lambdas can have their first parameter be treated as an implicit receiver inside the body. This affects name resolution in lambda body: implicit references to
this
of the declaring method are not available inside the body of a lambda.@
is used as an alias of the receiver parameter,this
is used to refer to the receiver of the declaring method and all symbols not resolved as lambda locals are resolved as implicit lambda receiver members before other options are tried.Methods indicate they accept lambdas with receivers by prefixing the parameter type with
this
, e.g.,Action<this Customer>
orFunc<this Customer, bool>
(this is later compiled as an attribute on the parameter). Such types cannot be used as types of locals, fields, return values or properties.Lambda declarations in positions where an implicit receiver lambda is expected omit this parameter altogether (i.e., single-parameter lambdas look like zero-parameter lambdas).
Such lambdas are not very useful by themselves, but serve as a stepping stone for the second change.
Zero parameter lambdas (including single parameter lambdas with implicit receivers) passed as the last parameter to a method call can be written outside the parentheses without
() =>
. If this invocation expression is being parsed as an expression statement then the semicolon is optional as well.When zero parameter lambdas are passed as any other parameter, they can still be written outside the parentheses without
() =>
as long as all other parameters are explicitly named.Return statements are disallowed in such lambda bodies to prevent confusion.
Expression-bodied lambdas must have their bodies wrapped in
{}
as well. If they are the only argument, then the parentheses are optional as well.:Examples:
Beta Was this translation helpful? Give feedback.
All reactions