[Proposal] Implicit lambda parameter and trailing lambda in C# #6122
Replies: 9 comments 15 replies
-
Very similar to #1151 Kotlin and Scala both have a flavor of this feature (or set of features which can be combined to achieve this kind of syntax) and it can be useful to define DSL-like syntax. Although, IMO, Scala takes it a bit too far as you can omit the dot operator (sometimes) and you can omit the parenthesis (sometimes). |
Beta Was this translation helpful? Give feedback.
-
#1151 went too far imo, it retargets what |
Beta Was this translation helpful? Give feedback.
-
@ronnygunawan wrll, your suggestion retargets |
Beta Was this translation helpful? Give feedback.
-
@orthoxerox well, I think both retargeting Kotlin and Java solve the |
Beta Was this translation helpful? Give feedback.
-
Is this on the consideration list for C# 11 / C# 12? 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. NOTE: Swift has since extended to support multiple trailing closures (full feature spec), thus directly supporting scenarios such as the example given above: STRETCH: Not sure if compatible with C# named parameters overall, but being able to optionally specify those as well would make it these much more readable/useful as well. Some very useful real-world examples from functional-style utilities: //
// EXAMPLE 1
//
// current lambdas
DateTimeOffset rangeEndDate = endDateTime?.IfNotNull( endDateTime_ =>
endDateTime_.StartOfDay() - ((crossesMidnight) ? 1 : 0).Days(),
otherwise: () => startDateTime.StartOfDay() );
// with trailing lambda
DateTimeOffset rangeEndDate = endDateTime?.IfNotNull(
value.StartOfDay() - ((crossesMidnight) ? 1 : 0).Days()
){ startDateTime.StartOfDay() };
// with multiple & named trailing lambdas (STRETCH)
DateTimeOffset rangeEndDate = endDateTime?.IfNotNull {
value.StartOfDay() - ((crossesMidnight) ? 1 : 0).Days()
}, otherwise: { startDateTime.StartOfDay() };
//
// EXAMPLE 2
//
// current lambdas
GeoCoordinate? coordinate = Try.CatchingAsNull<ArgumentOutOfRangeException, GeoCoordinate?>( () =>
new GeoCoordinate( place.geoCoordinate.latitude, place.geoCoordinate.longitude ),
@catch: x => { // NOTE: indentation hack to make it "feel" like a trailing lambda
Log.LogError( $"Geo-coordinate for content #{attraction.id} out of bounds: ({place.geoCoordinate.latitude}, {place.geoCoordinate.longitude}). Error: {x.Message}" );
});
// with trailing lambda
GeoCoordinate? coordinate = Try.CatchingAsNull<ArgumentOutOfRangeException, GeoCoordinate?>(
new GeoCoordinate( place.geoCoordinate.latitude, place.geoCoordinate.longitude )
){ // NOTE: no indentation hack. Trailing lambdas naturally style back to the containing statement's indentation
Log.LogError( $"Geo-coordinate for content #{place.id} out of bounds: ({place.geoCoordinate.latitude}, {place.geoCoordinate.longitude}). Error: {value.Message}" );
};
// with multiple & named trailing lambdas (STRETCH)
GeoCoordinate? coordinate = Try.CatchingAsNull<ArgumentOutOfRangeException, GeoCoordinate?>{
new GeoCoordinate( place.geoCoordinate.latitude, place.geoCoordinate.longitude )
}, @catch: x => {
Log.LogError( $"Geo-coordinate for content #{attraction.id} out of bounds: ({place.geoCoordinate.latitude}, {place.geoCoordinate.longitude}). Error: {x.Message}" );
}; |
Beta Was this translation helpful? Give feedback.
-
This could be very useful to convert code in fluent style into something easier to read and write. For example this FluentQuery
.ConnectionString("connectionString")
.StoredProcedure("LoadData")
.Parameters(c=>c
.AddParameter("ParName1", "ParValue1")
.AddParameter("ParName2", "ParValue3")
.AddParameter("ParName3", "ParValue3")
)
.Execute(); into this FluentQuery
.ConnectionString("connectionString")
.StoredProcedure("LoadData")
.Parameters
{
AddParameter("ParName1", "ParValue1")
AddParameter("ParName2", "ParValue3")
AddParameter("ParName3", "ParValue3")
}
.Execute(); or even this FluentQuery
{
ConnectionString("connectionString")
StoredProcedure("LoadData")
Parameters
{
AddParameter("ParName1", "ParValue1")
AddParameter("ParName2", "ParValue3")
AddParameter("ParName3", "ParValue3")
}
Execute()
}; It seems to me it looks much easier to write and read. |
Beta Was this translation helpful? Give feedback.
-
Would allow for much cleaner use of Parallel.ForEach and several AOP-like patterns, too. I support this. |
Beta Was this translation helpful? Give feedback.
-
I write a lot of code in Kotlin, where this syntax exists - and this is a game changer.
|
Beta Was this translation helpful? Give feedback.
-
So, is this conaidered for upcoming c# releases? |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Implicit lambda parameter:
() =>
when lambda has no parameter.arg1 =>
when lambda has only one parameter.() =>
andarg1 =>
, then implicit parameter can't be used.value
keyword.async
can be placed before the opening brace.this
is unaffected. It still refers to enclosing type.Trailing lambda:
Examples:
Functions
Actions
Method with multiple lambda
Get creative with trailing lambda
Beta Was this translation helpful? Give feedback.
All reactions