-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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] Allow extension methods to be used in the infix position #3673
Comments
I'm not sure that I see much benefit to this proposal. It doesn't really solve the LINQ extensibility issue as the scope under which LINQ queries execute is very different from extension methods (as you need to operate on the range, not the query). Beyond that it just appears to be trying to force a very non-C# syntax on top of C#. |
@HaloFour I believe the intention is that you could write something like: from x in list
select x ToList() Which would be translated to: (from x in list
select x).ToList() But that's the only place where I think this would make sense (and even then the syntax is not great; also it wouldn't work well for methods with lambda parameters like |
@metatron-the-chronicler What I mean is that with such methods, you want to be able to reference the range variable directly, without using the lambda syntax (similar to how you can reference them in For example, using a variant of the from person in people
select person
apply ToDictionary(person.Id, person.Name) Using your syntax, you would write: from person in people
select person ToDictionary(p => p.Id, p => p.Name) |
@svick I see. wouldn't such a case be solvable with let though? from person in people
let g=people ToDictionary(person.Id,person.Name)
select g; |
@metatron-the-chronicler Unless you're somehow completely changing the semantics of (Also, I can't see how could that compile anyway, since the |
@svick I thought we were talking about supposed syntax it would work fine if we used the real one which does require lambdas. The problem with your example is that you need to either declare a new dictionary in a projection or you need to use the actual collection since ToDictionary is defined on the source collection and not the temporary variable. You could also define a ToDictionary method directly on the person type to get this to work. Even with the current syntax your expression wouldn't produce the desired results because you need to generate the sequence of dictionaries and then take one. from c in collection
let g=collection ToDicitionary(c.id,c.name) //in real life you would use the lambda expression to access the properties you want need to be a lambda expression unless you made an overload for this kind of syntax.
select g Single |
@metatron-the-chronicler Even with modified syntax, |
@svick The thing is that the query expressions will always return some kind of Enumerable. Select (map) applies some function over a collection. You can't do what you are trying to pretty much by definition. The function you are applying to the sequence is (In this case at least.) logically created by all statements between from and select. In order for what you want to do to work you would have to treat the entire query expression as the argument to ToDictionary and take one element because ToDictionary would be applied to the generated Enumerable. You have to resolve the left hand expression to T from Enumerable regardless unless you do magic. |
I believe I can, for example using the Aggregate person In people
Into ToDictionary(person.Id) Though this doesn't work: Aggregate person In people
Into ToDictionary(person.Id, person.Name)
Yes, that's exactly what I want. Just like |
@svick your Aggregate example is fundamentally different from the one using select Aggregate returns T rather than Enumerable Select returns Enumerable that's why it doesn't make sense without first getting something that returns T. when you write from c in collection
where c.id >1
select c you are actually saying that you want a sequence that has had some function applied to the source collection. In the case of the above the function to be applied is a boolean that determines which elements have ids with values greater than one. Aggregate does something different. It takes elements and applies a function to them and produces a single result. With the apply example earlier apply has to put person into scope but it would still generate a sequence as opposed to a single dictionary value unless apply basically changes the whole meaning of the left operand (The query expression.) With this proposal the special context produced by from is no longer necessary. You could write var result=collection
Where (x=>x.id<500)
Select (r=> new{ some shaped result here}) Single The only thing to figure out is if it is possible without totally breaking everything to relax the requirements for parentheses and explicit arrows (x=>x) for lambda expressions. Though that is entirely optional. |
I think we'd be more likely to take #5445 instead of this proposal. |
We are now taking language feature discussion on https://github.com/dotnet/csharplang for C# specific issues, https://github.com/dotnet/vblang for VB-specific features, and https://github.com/dotnet/csharplang for features that affect both languages. |
It would be great if arbitrary functions defined on extension methods could be used in the infix (or postfix) position.
This would solve requests like #100 and make it possible to create cleaner dsls.
Technical
Consider:
Given this example this is the same as
If there are more arguments they must be given default values or there must be a valid overload that satisfies the minimum two arguments.
Postfix functions
The text was updated successfully, but these errors were encountered: