Replies: 35 comments 76 replies
-
previous discussion: https://github.com/dotnet/roslyn/issues/2060 notable things missing:
|
Beta Was this translation helpful? Give feedback.
-
Adding comment from issue #503: Expression Trees should be extended to support the C# 6.0 null propagating operator so that it can be used with Linq, with a translation to allow providers such as Linq to SQL to add support. The discussion on CodePlex doesn't seemed to have moved over to here, and has been sitting around for 3 years - I think it is worth revisiting, and ideally implementing. An ideal use case is an Outer Join in Linq to Objects. |
Beta Was this translation helpful? Give feedback.
-
+1 |
Beta Was this translation helpful? Give feedback.
-
I'd like to add my vote for this proposal for the sake of the Moq 4.x mocking library, whose API relies heavily on expression tree lambdas. In particular, support for the following two language features in expression tree lambda would be hugely beneficial to Moq. We could then fix the majority of currently reported bugs, and add some long requested features: I'm happy to further explain my reasons for prioritising these two, but don't want to go off on a tangent unbidden. |
Beta Was this translation helpful? Give feedback.
-
With the (awesome) addition of nullable reference types in C# 8.0 having null-propagation operation in expression trees goes from "very important" to "you almost can not use Entity Framework without this feature". Looking forward for knowing the design details of how this could be implemented in order to adapt my LINQ provider. |
Beta Was this translation helpful? Give feedback.
-
I wonder if local functions could be translated to SQL CTEs. |
Beta Was this translation helpful? Give feedback.
-
Bump. @gafter, I was wondering whether there's any news from the C# language team about this. I understand that it's probably more interesting to design and plan brand-new language features like Is there any chance this can be given a higher priority? Is there anything the community can do to help advance expression trees? |
Beta Was this translation helpful? Give feedback.
-
Async/await support is probably the largest undertaking on that list, but I'd love it. It would significantly help projects performing complex code-gen. |
Beta Was this translation helpful? Give feedback.
-
@scalablecory - I totally agree this would be nice. That being said, I question the likeihood of getting I think it would be awesome if we could just get the ball rolling, i. e. we could get agreement from the C# language team and/or the Roslyn team to look at the most basic missing features for a start. (I'd be happy to help in any way I reasonably can.) If we manage to get there, perhaps the more complex features will eventually follow, too. |
Beta Was this translation helpful? Give feedback.
-
It was discussed briefly on Monday... noting for example that we currently do not have support for /cc @dotnet/ldm It would help if we had a member of the LDM who championed this (even though it isn't technically a language feature). Any takers? |
Beta Was this translation helpful? Give feedback.
-
I think there would need to be a language change to support statements in expression trees because expression tree types explicitly states:
emphasis added. For everything else:
Should it be (libraries that walk these often assume specific patterns; the fact that according to the language spec they appear to be able to change between compiler versions is surprising isn't it)? (OT, it looks like there are numerous spaces missing from this document after the word "expression"; are PRs being accepted for these sorts of things yet?) |
Beta Was this translation helpful? Give feedback.
-
@bbarry PRs to fix typos in the spec are most welcome. |
Beta Was this translation helpful? Give feedback.
-
@gafer Is there any issue where the changes on the expression API are being discussed? |
Beta Was this translation helpful? Give feedback.
-
Not that I am aware |
Beta Was this translation helpful? Give feedback.
-
I don’t see ?. in expression trees anywhere in the selected features for c# 8. Any chance it will be included? Is considered a part of nullable reference types? I had three bugs in production because of SQL implicit nulls in left joins... What can we do to help this move forward? |
Beta Was this translation helpful? Give feedback.
-
Also, expression tree-like types proposal seems awesome: |
Beta Was this translation helpful? Give feedback.
-
I would like to propose ready-to-use extensions of Expression Trees presented in standard library:
This implementation can be used as a proof-of-concept for |
Beta Was this translation helpful? Give feedback.
-
according to https://github.com/dotnet/corefx/issues/33170 System.Linq.Expressions is archived meaning:
|
Beta Was this translation helpful? Give feedback.
-
https://github.com/dotnet/corefx/issues/32523 (Expression trees should support Span, stackalloc, ref struct ) was closed as "wont-fix" because Linq.Expressions is archived |
Beta Was this translation helpful? Give feedback.
-
I guess no one wants to maintain what is basically another version of the compiler, but at the moment no one on the LDT is willing to champion and prioritize a different solution for runtime code generation over other features either. |
Beta Was this translation helpful? Give feedback.
-
@orthoxerox Couldn't Roslyn itself be used for runtime code generation? Except that AFAICT Roslyn cannot be run in a single-threaded environment. |
Beta Was this translation helpful? Give feedback.
-
https://github.com/dotnet/csharplang/blob/main/meetings/2018/LDM-2018-06-06.md
That was 50 months ago :) |
Beta Was this translation helpful? Give feedback.
-
Given the discussion above it doesn't seem very probable that the present Creating a totally new expression tree abstraction whose design somehow avoids the extensibility issues of what we're dealing here? (What would be the point of abandoning SLE only to end up in the exact same situation in a few years' time, only the compiler team would then have two legacy expression tree models instead of one?) What would such a radical re-design have to look like? Or – I'm sure it's been discussed already, but I can't remember if & where I saw that idea – wouldn't it be possible to introduce an Roslyn extensibility point akin to source generators, which would allow user-code libraries to provide compile-time "code quotation factories" that turn a Roslyn AST of type The point of this idea being to make code quotations fully customizable and thereby shifting the maintenance burden away from the compiler into libraries which can be cleanly versioned. Those "quotation factories" could even signal (by emitting Roslyn diagnostics) what kind of expressions are supported / not supported by whatever target library the factories are associated with. (Whether or not When I last thought about this idea a few years ago, I thought it would stand no chance, since it might tie the C# spec too tightly to one implementation (namely Roslyn) because of the AST model required during transformation (you wouldn't want to invent yet another code tree model, right?)... but since then source generators have come into being; would this idea be so much different from them? |
Beta Was this translation helpful? Give feedback.
-
A lot of the concern on this thread speaks to the use of expression trees in EF, but I also wanted to highlight their extensive use in the somewhat recently open-sourced Reaqtive project. This project provides a platform for hosted reactive operations allowing for stateful stateful checkpointing and recovery of standing and active subscriptions. It provides libraries for serialization of expression trees (allowing for queries and their components to be saved in stateful storage while at rest), which is huge in itself. However, the implementation of and extendibility of the observers and observables could be made dramatically simpler if .NET had support for async expression trees, so I'd ask that these be considered in the next overhaul of expression trees, whatever shape that takes. I understand the argument in here for breaking old dependencies on existing expression trees, but I don't necessarily see why this isn't something that is run in the .NET Core style of move-faster-likely-breaking-things as things transitioned from .NET 4 to .NET 5. Given that the implementation of each of the proposed changes is thought to be pretty straightforward and because Bart has already done some exploration in what might be needed to support different branches of support with the ExpressionTreeLike types and even has a sample implementation of this, why can this not simply be something that is opt-in, similar to that of the nullability flag in csproj wherein developers can choose to use the legacy expression tree (selected by default) or can opt into a more modern expression tree that will continually evolve as C# does. I don't know to what extent .NET is able to do feature flags, as it were, in the code, but what if modern expression support were an opt-in on a feature-by-feature basis? Today, my .csproj contains: <PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup> Why can't modern expression trees be similar? This would enable all available modern expression tree functionality (similar to setting language support to vNext in that it's likely something will break with new changes). <PropertyGroup>
<ModernExpressions>true</ModernExpressions>
</PropertyGroup> And especially since there's such a laundry list of individual features, allow them to be opt-in by name: <PropertyGroup>
<ModernExpressions>
<NullCoaselscing>true</NullCoalescing>
<Async>true</Async>
<Dynamic>true</Dynamic>
</ModernExpressions>
</PropertyGroup> Those features that are inextricably linked to all of them are included just by enabling ModernExpressions (doesn't happen often, but does happen per the opt-in contract). But this means you don't have to enable all the new features all at once in a single release and trivially opens the door to revisiting to add new expressions features in a way that people can use if they want or simply opt-out of. At launch, there's zero net impact until developers decide to proactively opt into the new functionality - a great many will, but if their application breaks, I suspect they'll be more reasonable about the migration. After launch, there's some impact as developers upgrade packages indiscriminately, but the analyzer saves them from themselves here. And in the longer-term, new applications get to enjoy rich expression tree support and older applications keep on using the legacy approach. |
Beta Was this translation helpful? Give feedback.
-
It's strange that something as important as this is not even being discussed. What's blocking this?! |
Beta Was this translation helpful? Give feedback.
-
Found this discussion while writing yet another EF query that required me to do .Select(x => new Dto {
Foo = x.Foo == null ? x.Date : x.Foo
}) instead of the sane thing, .Select(x => new Dto {
Foo = x.Foo ?? x.Date
}) and I'm guessing I'll have to use it a while longer still |
Beta Was this translation helpful? Give feedback.
-
Having just re-read this entire thread, all the while carefully considering the concerns and explanations provided by the likes of @CyrusNajmabadi, @333fred, et al. I must say they are making about as much sense as how many "new" C# syntactic features have had support added for them in expression trees over the last decade or so, which is, of course, a glorious zero. Let's consider this comment by @333fred — as I think it succinctly and clearly presents the supposed justification:
(emphasis mine) Sounds reasonable, right? Except that it should take no more than 5 seconds for anyone remotely familiar with C#/.NET's and the surrounding ecosystem's progression over the last couple of years, to realize two things, which immediately obliterate this reasoning: Swap the terms "new node" with "new built-in anything" and you'll get an equally sound argument for never adding any feature at any level in any area to the framework/standard library ever; because "what about existing tools that won't immediately support it?", I guess. It is unbelievably unconvincing. There is literally a fundamental analogy here between any hypothetical new expression nodes, and any new standard constructs in general — with the most notable recent example being what happened with Notice that according to the same logic as the one that we're being provided here as to why expressions are stuck at the C# of 10 years ago, apparently the addition of
It gets even worse, this argument is, in fact, even LESS applicable in the case of expression trees, because all consumers of expression trees (most prominently EF), ALREADY ONLY support a subset of "all possible expression trees". An expression tree consumer not supporting a certain thing at a given time is already the status quo, and as such, fully expected. Funny. Some people in this thread (e.g. @olmobrutall here) tried to point out the same thing, heck, even some comments on related Stack Overflow questions made this point, and made more basic logical sense than anyone from the other side here. I'm just trying to help reveal the folly in this reasoning more clearly and bring more awareness to the issue. |
Beta Was this translation helpful? Give feedback.
-
Breaking out a tangent, but: Is there a reason a "new" expression tree system couldn't be "just" a 1:1 mapping of the AST itself? Why do they need to be representative of the "lowered" code? I hate to bring Rust into this, but the input to their "proc macros" are nothing more than a (brace-balanced) token stream. It doesn't even need to be legal Rust syntax. I know expression trees aren't designed for this, but they're almost perfect for creating DSLs — you can write an interpreter around the nodes to parse out logic. That's basically what EF consumers are doing — turning a C#-like DSL into SQL. And, as C# continues to evolve, this C#-like DSL continues to stray further and further away. If expression trees were merely the AST without any "lowering", you could write much more powerful DSLs, and you wouldn't need to be worried about how compiler optimizations affect the output tree — because the AST comes before optimization. Basically, rip off the band-aid and create something new. Such a new system would obviously need to be documented as non-exhaustive, and developers should be encouraged to document what their inputs must be. But by being the AST, and not the lowered/optimized code, new compiler optimizations won't affect inputs. In the future — perhaps — macros could be explored as, essentially, Roslyn preprocessors, using this AST. |
Beta Was this translation helpful? Give feedback.
-
Hello, just wanting to make sure I'm on the same page, since there are seemingly two different discussions going on. Forgive me if this is re-hashing the old points again, but I feel this might help more than me. There are fundamentally two different parts to this discussion. Things Currently Supported By Raw Expression Nodes, But Not Supported In Lambda ExpressionsThis includes things like CSharpExpressions was already mentioned as an example of solving some of those by implementing new nodes, but allowing most nodes to be reduced to a more complex tree using existing expression nodes. However, another example which does get used in production is LINQKit. Because it's the only way I can easily call a typed lambda expression from another lambda expression. Things Not Currently Supported By Raw Expression NodesThese are things which would explicitly require new node types to work. An example noted by CSharpExpressions is below.
My Issue / QuestionSomeone please correct me if I am misunderstanding, but I don't understand the controversy of fixing the first issue. The only possible downside is it would allow someone to more easily write expressions which contain some node types not supported by all query transformers. However, it is possible today to write those same not supported expressions today. They just have to be done by hand. Meanwhile, the convenience of the null-coalescing operator ( Plus, without LINQKit everything either has to be in one large lambda, violating almost every code readability standard out there, or everything which calls something else must be a hand constructed expression. Which is something most C# programmers, including the rest of my team, aren't familiar with and can't work on. Would someone please explain to me why fixing this first issue is so controversial. |
Beta Was this translation helpful? Give feedback.
-
You should just rip off the bandaid and start pushing updates to the API. If you want to play it safe - do it on a small surface area of new language features to give the community / providers time to update for compatibility. Then on the next C# release push out the next wave of updates once library authors get the gist of what’s to come. Stop overprotecting the community though. We will pick up the pieces. PR’s will be raised, compatibility issues will be fixed. In MUCH less time than it takes you guys to debate all the downsides of how to minimized breakage. Let’s get on with it already! |
Beta Was this translation helpful? Give feedback.
-
Expression trees today support a limited subset of expression lambdas. This issue is to track the request to extend them to support more or all of the language constructs that can be expressed in a lambda.
A prototype for work in this direction can be found on https://github.com/bartdesmet/ExpressionFutures/tree/master/CSharpExpressions and https://github.com/bartdesmet/roslyn/tree/ExpressionTrees (based on a fork of Roslyn a while ago).
/cc @bartdesmet
Beta Was this translation helpful? Give feedback.
All reactions